changeset 152:240aa6994018 v2

component model refactoring
author cin
date Thu, 11 Feb 2016 01:56:27 +0300
parents ec91a6dfa5b3
children b933ec88446e
files Implab/Component.cs Implab/ComponentContainer.cs Implab/Components/App.cs Implab/Components/ComponentContainer.cs Implab/Components/Disposable.cs Implab/Components/DisposablePool.cs Implab/Components/ExecutionState.cs Implab/Components/IInitializable.cs Implab/Components/IRunnable.cs Implab/Components/ObjectPool.cs Implab/Components/ServiceLocator.cs Implab/Diagnostics/ListenerBase.cs Implab/Disposable.cs Implab/DisposablePool.cs Implab/IComponentContainer.cs Implab/Implab.csproj Implab/ObjectPool.cs Implab/Parsing/Scanner.cs Implab/ServiceLocator.cs
diffstat 19 files changed, 667 insertions(+), 608 deletions(-) [+]
line wrap: on
line diff
--- a/Implab/Component.cs	Thu Feb 04 02:43:05 2016 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Web;
-
-namespace Implab {
-    /// <summary>
-    /// Компоненты являются состовными объектами, имеют детерминированный период жизни, автоматически освобождают ресурсы входящие в них.
-    /// </summary>
-    /// <remarks>Компонента управляет временем жизни включенных в нее компонент</remarks>
-    public class Component: Disposable {
-        LinkedList<IDisposable> m_components = new LinkedList<IDisposable>();
-
-        /// <summary>
-        /// Коллекция компонент, из которых состоит текущая компонента.
-        /// </summary>
-        public ICollection<IDisposable> Components {
-            get {
-                AssertNotDisposed();
-                return m_components;
-            }
-        }
-
-        /// <summary>
-        /// Освобождает компоненты, входящие в состав текущей компоненты.
-        /// </summary>
-        /// <param name="disposing">Признак того, что происходит освобождение ресурсов.</param>
-        protected override void Dispose(bool disposing) {
-            if (disposing) {
-                foreach (var item in m_components)
-                    item.Dispose();
-                m_components.Clear();
-            }
-            base.Dispose(disposing);
-        }
-    }
-}
\ No newline at end of file
--- a/Implab/ComponentContainer.cs	Thu Feb 04 02:43:05 2016 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-using System;
-using Implab.Parallels;
-using System.Threading;
-
-namespace Implab {
-    public class ComponentContainer : IComponentContainer, IDisposable {
-        static readonly ComponentContainer _appContainer;
-
-        static ComponentContainer() {
-            _appContainer = new ComponentContainer();
-            AppDomain.CurrentDomain.ProcessExit += HandleProcessExit;
-        }
-
-        public static ComponentContainer Global {
-            get {
-                return _appContainer;
-            }
-        }
-
-        bool m_disposed;
-        readonly AsyncQueue<IDisposable> m_components = new AsyncQueue<IDisposable>();
-
-        public void Add(IDisposable item) {
-            Safe.ArgumentNotNull(item, "item");
-            Thread.MemoryBarrier();
-            if (m_disposed) {
-                item.Dispose();
-            } else {
-                m_components.Enqueue(item);
-                if (m_disposed && m_components.TryDequeue(out item))
-                    item.Dispose();
-            }
-        }
-
-        public void Dispose() {
-            m_disposed = true;
-            IDisposable item;
-            while (m_components.TryDequeue(out item))
-                item.Dispose();
-        }
-
-        static void HandleProcessExit (object sender, EventArgs e)
-        {
-            _appContainer.Dispose();
-        }
-    }
-}
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab/Components/App.cs	Thu Feb 11 01:56:27 2016 +0300
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+
+namespace Implab.Components {
+    /// <summary>
+    /// Global application components and services.
+    /// </summary>
+    public static class App {
+        readonly static ComponentContainer<object> _root = new ComponentContainer<object>();
+
+        public static ICollection<object> RootContainer {
+            get { return _root; }
+        }
+
+        static App() {
+            AppDomain.CurrentDomain.ProcessExit += (sender, e) => _root.Dispose();
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab/Components/ComponentContainer.cs	Thu Feb 11 01:56:27 2016 +0300
@@ -0,0 +1,84 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Implab.Components {
+    /// <summary>
+    /// Component container.
+    /// </summary>
+    /// <remarks>Instanses of this class are thread safe.</remarks>
+    public class ComponentContainer<T> : Disposable, ICollection<T> {
+        readonly HashSet<T> m_components = new HashSet<T>();
+
+        public void Clear() {
+            T[] removed;
+
+            lock (m_components) {
+                removed = new T[m_components.Count];
+                m_components.CopyTo(removed);
+                m_components.Clear();
+            }
+
+            foreach (var item in removed.OfType<IDisposable>())
+                item.Dispose();
+        }
+
+        public bool Contains(T item) {
+            lock (m_components)
+                return m_components.Contains(item);
+        }
+
+        public void CopyTo(T[] array, int arrayIndex) {
+            lock (m_components)
+                m_components.CopyTo(array, arrayIndex);
+        }
+
+        public bool Remove(T item) {
+            lock (m_components)
+                return m_components.Remove(item);
+        }
+
+        public int Count {
+            get {
+                lock (m_components)
+                    return m_components.Count;
+            }
+        }
+
+        public bool IsReadOnly {
+            get {
+                return false;
+            }
+        }
+
+        public IEnumerator<T> GetEnumerator() {
+            T[] items;
+            lock (m_components) {
+                items = new T[m_components.Count];
+                m_components.CopyTo(items);
+                return (IEnumerator<T>)items.GetEnumerator();
+            }
+        }
+
+        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
+            return GetEnumerator();
+        }
+
+        public void Add(T item) {
+            Safe.ArgumentNotNull(item, "item");
+
+            lock (m_components) {
+                if (IsDisposed)
+                    Safe.Dispose(item);
+                else
+                    m_components.Add(item);
+            }
+        }
+
+        protected override void Dispose(bool disposing) {
+            base.Dispose(disposing);
+            Clear();
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab/Components/Disposable.cs	Thu Feb 11 01:56:27 2016 +0300
@@ -0,0 +1,103 @@
+using Implab.Diagnostics;
+using System;
+using System.Threading;
+
+namespace Implab.Components {
+    /// <summary>
+    /// Base class the objects which support disposing.
+    /// </summary>
+    public class Disposable : IDisposable {
+        
+        int m_disposed;
+
+        public event EventHandler Disposed;
+
+        public bool IsDisposed {
+            get {
+                Thread.MemoryBarrier();
+                return m_disposed != 0;
+            }
+        }
+
+        /// <summary>
+        /// Asserts the object is not disposed.
+        /// </summary>
+        /// <exception cref="ObjectDisposedException">The object is disposed</exception>
+        /// <remarks>
+        /// Успешная проверка того, что объект не освобожден еще не гарантирует, что он не
+        /// будет освобожден сразу после нее, поэтому методы использующие проверку должны
+        /// учитывать, что объект может быть освобожден из параллельного потока.
+        /// Данны метод служит для упрощения отладки ошибок при использовании объекта после его
+        /// освобождения.
+        /// </remarks>
+        /// <example>
+        /// // пример синхронизированного освобождения ресурсов
+        /// class FileStore : Disposable {
+        ///     readonly TextWriter m_file;
+        ///     readonly obejct m_sync = new object();
+        /// 
+        ///     public FileStore(string file) {
+        ///         m_file = new TextWriter(File.OpenWrite(file));
+        ///     }
+        /// 
+        ///     public void Write(string text) {
+        ///         lock(m_sync) {
+        ///             AssertNotDisposed();
+        ///             m_file.Write(text);
+        ///         }
+        ///     }
+        /// 
+        ///     protected override void Dispose(bool disposing) {
+        ///         if (disposing)
+        ///             lock(m_sync) {
+        ///                 m_file.Dipose();
+        ///                 base.Dispose(true);
+        ///             }
+        ///         else
+        ///             base.Dispose(false);
+        ///     }
+        /// }
+        /// <example> 
+        protected void AssertNotDisposed() {
+            Thread.MemoryBarrier();
+            if (m_disposed != 0)
+                throw new ObjectDisposedException(ToString());
+        }
+        /// <summary>
+        /// Вызывает событие <see cref="Disposed"/>
+        /// </summary>
+        /// <param name="disposing">Признак того, что нужно освободить ресурсы, иначе данный метод
+        /// вызван сборщиком мусора и нужно освобождать ТОЛЬКО неуправляемые ресурсы ТОЛЬКО этого
+        /// объекта.</param>
+        /// <remarks>
+        /// Данный метод вызывается гарантированно один раз даже при одновременном вызове <see cref="Dispose()"/>
+        /// из нескольких потоков.
+        /// </remarks>
+        protected virtual void Dispose(bool disposing) {
+            if (disposing) {
+                EventHandler temp = Disposed;
+                if (temp != null)
+                    temp(this, EventArgs.Empty);
+            }
+        }
+
+        public void Dispose() {
+            if (Interlocked.Increment(ref m_disposed) == 1) {
+                Dispose(true);
+                GC.SuppressFinalize(this);
+            }
+        }
+
+        /// <summary>
+        /// Записывает сообщение об утечке объекта.
+        /// </summary>
+        protected virtual void ReportObjectLeaks() {
+            TraceLog.TraceWarning("The object is marked as disposable but isn't disposed properly: {0}", this);
+        }
+
+        ~Disposable() {
+            Dispose(false);
+            ReportObjectLeaks();
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab/Components/DisposablePool.cs	Thu Feb 11 01:56:27 2016 +0300
@@ -0,0 +1,90 @@
+using System;
+using Implab.Parallels;
+using System.Threading;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+
+namespace Implab {
+    public abstract class DisposablePool<T> : IDisposable {
+        readonly int m_size;
+        readonly AsyncQueue<T> m_queue = new AsyncQueue<T>();
+
+        [SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")]
+        static readonly bool _isValueType = typeof(T).IsValueType;
+
+        bool m_disposed;
+
+        int m_count;
+
+        protected DisposablePool(int size) {
+            m_size = size;
+        }
+
+        protected DisposablePool() : this(Environment.ProcessorCount+1) {
+        }
+
+        public T Allocate() {
+            if (m_disposed)
+                throw new ObjectDisposedException(ToString());
+
+            T instance;
+            if (m_queue.TryDequeue(out instance)) {
+                Interlocked.Decrement(ref m_count);
+            } else {
+                instance = CreateInstance();
+                Debug.Assert(!Object.Equals(instance, default(T)) || _isValueType);
+            }
+            return instance;
+        }
+
+        protected abstract T CreateInstance();
+
+        protected virtual void CleanupInstance(T instance) {
+        }
+
+        public void Release(T instance) {
+            if ( Object.Equals(instance,default(T)) && !_isValueType)
+                return;
+
+            Thread.MemoryBarrier();
+            if (m_count < m_size && !m_disposed) {
+                Interlocked.Increment(ref m_count);
+
+                CleanupInstance(instance);
+
+                m_queue.Enqueue(instance);
+
+                // пока элемент возвращался в кеш, была начата операция освобождения всего кеша
+                // и возможно уже законцена, в таком случае следует извлечь элемент обратно и
+                // освободить его. Если операция освобождения кеша еще не заврешилась, то будет
+                // изъят и освобожден произвольный элемен, что не повлияет на ход всего процесса.
+                if (m_disposed && m_queue.TryDequeue(out instance) && instance is IDisposable)
+                    ((IDisposable)instance).Dispose() ;
+
+            } else {
+                if (instance is IDisposable)
+                    ((IDisposable)instance).Dispose();
+            }
+        }
+
+        protected virtual void Dispose(bool disposing) {
+            if (disposing) {
+                m_disposed = true;
+                T instance;
+                while (m_queue.TryDequeue(out instance))
+                    if (instance is IDisposable)
+                        ((IDisposable)instance).Dispose();
+            }
+        }
+
+        #region IDisposable implementation
+
+        public void Dispose() {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        #endregion
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab/Components/ExecutionState.cs	Thu Feb 11 01:56:27 2016 +0300
@@ -0,0 +1,12 @@
+namespace Implab.Components {
+    public enum ExecutionState {
+        Uninitialized,
+        Initial,
+        Starting,
+        Running,
+        Stopping,
+        Stopped,
+        Disposed,
+        Failed
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab/Components/IInitializable.cs	Thu Feb 11 01:56:27 2016 +0300
@@ -0,0 +1,21 @@
+using System;
+
+namespace Implab.Components {
+    /// <summary>
+    /// Initializable components are created and initialized in two steps, first we have create the component,
+    /// then we have to complete it's creation by calling an <see cref="Init()"/> method. All parameters needed
+    /// to complete the initialization must be passed before the calling <see cref="Init()"/>
+    /// </summary>
+    public interface IInitializable {
+        /// <summary>
+        /// Completes initialization.
+        /// </summary>
+        /// <remarks>
+        /// Normally virtual shouldn't be called from the constructor, due to the incomplete object state, but
+        /// they can be called from this method. This method is also usefull when we constructing a complex grpah
+        /// of components where cyclic references may take place.
+        /// </remarks>
+        void Init();
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab/Components/IRunnable.cs	Thu Feb 11 01:56:27 2016 +0300
@@ -0,0 +1,14 @@
+using System;
+
+namespace Implab.Components {
+    public interface IRunnable {
+        IPromise Start();
+
+        IPromise Stop();
+
+        ExecutionState State { get; }
+
+        Exception LastError { get; }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab/Components/ObjectPool.cs	Thu Feb 11 01:56:27 2016 +0300
@@ -0,0 +1,60 @@
+using Implab.Parallels;
+using System;
+using System.Threading;
+
+namespace Implab.Components {
+    /// <summary>
+    /// Базовый класс для создания пулов объектов.
+    /// </summary>
+    /// <remarks>
+    /// <para>Пул объектов позволяет многократно использовать один и тотже объект,
+    /// что актуально для объектов, создание которых требует существенных ресурсов.
+    /// Пул объектов использует слабые ссылки, чтобы не препятствовать освобождению
+    /// ресурсов и создает новые объекты при необходимости.</para>
+    /// <para>
+    /// Наследники должны реализовывать метод <see cref="CreateInstance()"/> для создания
+    /// новых экземпляров.
+    /// </para>
+    /// <para>Пул поддерживает обращения сразу из нескольких потоков.</para>
+    /// </remarks>
+    public abstract class ObjectPool<T> where T : class {
+        readonly AsyncQueue<WeakReference> m_queue = new AsyncQueue<WeakReference>();
+        readonly int m_size;
+        int m_count = 0;
+
+        protected ObjectPool() : this(Environment.ProcessorCount+1) {
+
+        }
+
+        protected ObjectPool(int size) {
+            Safe.ArgumentInRange(size,1,size,"size");
+
+            m_size = size;
+        }
+
+        protected abstract T CreateInstance();
+
+        protected virtual void CleanupInstance(T instance) {
+        }
+
+        public T Allocate() {
+            WeakReference reference;
+            while (m_queue.TryDequeue(out reference)) {
+                Interlocked.Decrement(ref m_count);
+                object instance = reference.Target;
+                if (instance == null)
+                    continue;
+                return (T)instance;
+            }
+            return CreateInstance();
+        }
+
+        public void Release(T instance) {
+            if (m_count < m_size && instance != null) {
+                Interlocked.Increment(ref m_count);
+                CleanupInstance(instance);
+                m_queue.Enqueue(new WeakReference(instance));
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab/Components/ServiceLocator.cs	Thu Feb 11 01:56:27 2016 +0300
@@ -0,0 +1,248 @@
+using System;
+using System.Collections.Generic;
+
+namespace Implab.Components {
+    /// <summary>
+    /// Коллекция сервисов, позволяет регистрировать и получать сервисы.
+    /// </summary>
+    public class ServiceLocator: Disposable, IServiceLocator, IServiceProvider {
+        // запись о сервисе
+        struct ServiceEntry : IDisposable {
+            public object service; // сервис
+            public bool shared; // признак того, что сервис НЕ нужно освобождать
+            public Func<object> activator; // активатор сервиса при первом обращении
+            public Action<object> cleanup; // функция для очистки сервиса
+            public List<Type> associated; // ссылки на текущую запись
+            public Type origin; // ссылка на оригинальную запись о сервисе
+
+            #region IDisposable implementation
+
+            public void Dispose() {
+                if (shared)
+                    return;
+                if (cleanup != null) {
+                    if (service != null)
+                        cleanup(service);
+                } else
+                    Safe.Dispose(service);
+            }
+
+            #endregion
+        }
+
+        // словарь существующих сервисов
+        readonly Dictionary<Type, ServiceEntry> m_services = new Dictionary<Type,ServiceEntry>();
+
+        /// <summary>
+        /// Получает объект предоставляющий сервис <typeparamref name="T"/>.
+        /// </summary>
+        /// <typeparam name="T">Тип запрашиваемого сервиса</typeparam>
+        /// <returns>Объект, реализующий сервис</returns>
+        /// <exception cref="KeyNotFoundException">Сервис не зарегистрирован</exception>
+        public T GetService<T>() {
+            object result;
+            if (TryGetService(typeof(T), out result))
+                return (T)result;
+            throw new ApplicationException (String.Format ("{0} doesn't provide {1} service", this, typeof(T)));
+        }
+
+
+        /// <summary>
+        /// Пытается получить указанный сервис, в случае, если компонента не предоставляет требуемый сервис
+        /// не возникает исключений.
+        /// </summary>
+        /// <typeparam name="T">Тип требуемого сервиса.</typeparam>
+        /// <param name="service">Объект реализующий сервис, или <c>default(T)</c> если такового нет.</param>
+        /// <returns><c>true</c> - сервис найден, <c>false</c> - сервис не зарегистрирован.</returns>
+        public bool TryGetService<T>(out T service) {
+            object result;
+            if (TryGetService(typeof(T), out result)) {
+                service = (T)result;
+                return true;
+            }
+            service = default(T);
+            return false;
+        }
+
+        /// <summary>
+        /// Получает объект предоставляющий сервис <paramref name="serviceType"/>
+        /// </summary>
+        /// <param name="serviceType">Тип запрашиваемого сервиса</param>
+        /// <returns>Объект, реализующий сервис</returns>
+        /// <exception cref="KeyNotFoundException">Сервис не зарегистрирован</exception>
+		public object GetService(Type serviceType) {
+            object result;
+            if (TryGetService(serviceType, out result))
+                return result;
+			throw new ApplicationException (String.Format ("{0} doesn't provide {1} service", this, serviceType));
+		}
+
+		/// <summary>
+		/// Пытается получить требуемый сервис или совместимый с ним.
+		/// </summary>
+		/// <returns><c>true</c>, если сервис был найден, <c>false</c> в противном случае..</returns>
+		/// <param name="serviceType">Тип запрашиваемого сервиса.</param>
+		/// <param name="service">Искомый сервис.</param>
+		public virtual bool TryGetService(Type serviceType, out object service) {
+            Safe.ArgumentNotNull(serviceType, "serviceType");
+            AssertNotDisposed();
+
+            ServiceEntry se;
+            if (!m_services.TryGetValue(serviceType, out se)) {
+                // ищем ближайщий объект, реализующий нужный сервис
+                Type pt = null;
+                foreach (var t in m_services.Keys)
+                    if (serviceType.IsAssignableFrom(t) && (pt == null || t.IsAssignableFrom(pt)))
+                        pt = t;
+
+				if (pt == null) {
+					// нет нужного сервиса
+					service = null;
+					return false;
+				}
+
+                var pe = m_services[pt];
+
+                // найденная запись может ссылаться на оригинальную запись с сервисом
+                if(pe.origin != null) {
+                    pt = pe.origin;
+                    pe = m_services[pt];
+                }
+                    
+                // добавляем список с обратными ссылками
+                if (pe.associated == null)
+                    pe.associated = new List<Type>();
+
+                pe.associated.Add(serviceType);
+
+                // обновляем родительскую запись
+                m_services[pt] = pe;
+
+                // создаем запись со ссылкой
+                se = new ServiceEntry {
+                    service = pe.service,
+                    origin = pt,
+                    shared = true // предотвращаем множественные попытки освобождения
+                };
+
+                m_services[serviceType] = se;
+            }
+
+            // запись содержит в себе информацию о сервисе
+			if (se.service != null) {
+				service = se.service;
+				return true;
+			}
+
+            // текущая запись является ссылкой
+            if (se.origin != null) {
+                se.service = GetService(se.origin);
+                m_services[serviceType] = se;
+				service = se.service;
+				return true;
+            }
+
+            // текущая запись не является ссылкой и не имеет информации о сервисе
+            // она должна сожержать информацию об активации
+            if (se.activator != null) {
+                se.service = se.activator();
+
+                m_services[serviceType] = se;
+
+				service = se.service;
+				return true;
+            }
+
+			service = null;
+			return false;
+        }
+
+        /// <summary>
+        /// Регистрирует фабрику для активации сервиса по первому требованию.
+        /// </summary>
+        /// <typeparam name="T">Тип регистрируемого сервиса.</typeparam>
+        /// <param name="activator">Фабрика для создания/получения объекта, предоставляющего сервис.</param>
+        /// <param name = "cleanup">Метод для освобождения экземпляра сервиса, будет вызыван при освобождении сервис-локатора.</param>
+        /// <remarks>При освобождении сервис-локатора, сервисы полученные в результате активации также будут освобождены.</remarks>
+        public void Register<T>(Func<T> activator, Action<T> cleanup) {
+            Safe.ArgumentNotNull(activator, "activator");
+
+            AssertNotDisposed();
+
+            Unregister(typeof(T));
+            
+            var serviceEntry = new ServiceEntry();
+            serviceEntry.activator = () => activator();
+            if (cleanup != null)
+                serviceEntry.cleanup = instance => cleanup((T)instance);
+            m_services[typeof(T)] = serviceEntry;
+        }
+
+        public void Register<T>(Func<T> activator) {
+            Register(activator, null);
+        }
+
+        /// <summary>
+        /// Регистрирует объект, предоставляющий сервис.
+        /// </summary>
+        /// <typeparam name="T">Тип регистрируемого сервиса.</typeparam>
+        /// <param name="service">Объект, предоставляющий сервис.</param>
+        /// <exception cref="InvalidOperationException">Указанный сервис уже зарегистрирован.</exception>
+        /// <remarks>Сервис-локатором не управляет временем жизни объекта для зарегистрированного сервиса.</remarks>
+        public void Register<T>(T service) {
+            Register(service, true);
+        }
+
+        /// <summary>
+        /// Регистрирует объект, предоставляющий сервис. Повторная регистрация отменяет уже существующую.
+        /// </summary>
+        /// <typeparam name="T">Тип регистрируемого сервиса.</typeparam>
+        /// <param name="service">Объект, предоставляющий сервис.</param>
+        /// <param name="shared">Признак того, что объект является разделяемым и сервис-локатор не должен его освобождать.</param>
+        public void Register<T>(T service, bool shared) {
+            Safe.ArgumentNotNull(service, "service");
+
+            AssertNotDisposed();
+
+            Unregister(typeof(T));
+            
+            m_services[typeof(T)] = new ServiceEntry { service = service, shared = shared };
+        }
+
+        public void Unregister(Type serviceType) {
+            Safe.ArgumentNotNull(serviceType, "serviceType");
+
+            AssertNotDisposed();
+            
+            ServiceEntry se;
+            if (m_services.TryGetValue(serviceType, out se)) {
+                if (se.origin != null) {
+                    var pe = m_services[se.origin];
+                    pe.associated.Remove(serviceType);
+                }
+                // освобождаем ресурсы
+                se.Dispose();
+                m_services.Remove(serviceType);
+
+                // убираем связанные записи
+                if (se.associated != null)
+                    foreach (var item in se.associated)
+                        m_services.Remove(item);
+            }
+        }
+
+        /// <summary>
+        /// Освобождает зарегистрированные сервисы (которые требуется освобоить).
+        /// </summary>
+        /// <param name="disposing">Призанак того, что нужно освободить ресурсы.</param>
+        protected override void Dispose(bool disposing) {
+            if (disposing) {
+
+                foreach (var entry in m_services.Values)
+                    entry.Dispose();
+
+            }
+            base.Dispose(disposing);
+        }
+    }
+}
\ No newline at end of file
--- a/Implab/Diagnostics/ListenerBase.cs	Thu Feb 04 02:43:05 2016 +0300
+++ b/Implab/Diagnostics/ListenerBase.cs	Thu Feb 11 01:56:27 2016 +0300
@@ -1,7 +1,6 @@
 using System;
 using System.Collections.Generic;
-using System.Linq;
-using System.Text;
+using Implab.Components;
 
 namespace Implab.Diagnostics {
     public abstract class ListenerBase : ServiceLocator, ILogWriter<object>, ILogWriter<TraceEvent> {
--- a/Implab/Disposable.cs	Thu Feb 04 02:43:05 2016 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,104 +0,0 @@
-using Implab.Diagnostics;
-using System;
-using System.Threading;
-using System.IO;
-
-namespace Implab {
-    /// <summary>
-    /// Объект, поддерживающий освобождение ресурсов.
-    /// </summary>
-    public class Disposable : IDisposable {
-        
-        int m_disposed;
-
-        public event EventHandler Disposed;
-
-        public bool IsDisposed {
-            get {
-                Thread.MemoryBarrier();
-                return m_disposed != 0;
-            }
-        }
-
-        /// <summary>
-        /// Asserts the object is not disposed.
-        /// </summary>
-        /// <exception cref="ObjectDisposedException">The object is disposed</exception>
-        /// <remarks>
-        /// Успешная проверка того, что объект не освобожден еще не гарантирует, что он не
-        /// будет освобожден сразу после нее, поэтому методы использующие проверку должны
-        /// учитывать, что объект может быть освобожден из параллельного потока.
-        /// Данны метод служит для упрощения отладки ошибок при использовании объекта после его
-        /// освобождения.
-        /// </remarks>
-        /// <example>
-        /// // пример синхронизированного освобождения ресурсов
-        /// class FileStore : Disposable {
-        ///     readonly TextWriter m_file;
-        ///     readonly obejct m_sync = new object();
-        /// 
-        ///     public FileStore(string file) {
-        ///         m_file = new TextWriter(File.OpenWrite(file));
-        ///     }
-        /// 
-        ///     public void Write(string text) {
-        ///         lock(m_sync) {
-        ///             AssertNotDisposed();
-        ///             m_file.Write(text);
-        ///         }
-        ///     }
-        /// 
-        ///     protected override void Dispose(bool disposing) {
-        ///         if (disposing)
-        ///             lock(m_sync) {
-        ///                 m_file.Dipose();
-        ///                 base.Dispose(true);
-        ///             }
-        ///         else
-        ///             base.Dispose(false);
-        ///     }
-        /// }
-        /// <example> 
-        protected void AssertNotDisposed() {
-            Thread.MemoryBarrier();
-            if (m_disposed != 0)
-                throw new ObjectDisposedException(ToString());
-        }
-        /// <summary>
-        /// Вызывает событие <see cref="Disposed"/>
-        /// </summary>
-        /// <param name="disposing">Признак того, что нужно освободить ресурсы, иначе данный метод
-        /// вызван сборщиком мусора и нужно освобождать ТОЛЬКО неуправляемые ресурсы ТОЛЬКО этого
-        /// объекта.</param>
-        /// <remarks>
-        /// Данный метод вызывается гарантированно один раз даже при одновременном вызове <see cref="Dispose()"/>
-        /// из нескольких потоков.
-        /// </remarks>
-        protected virtual void Dispose(bool disposing) {
-            if (disposing) {
-                EventHandler temp = Disposed;
-                if (temp != null)
-                    temp(this, EventArgs.Empty);
-            }
-        }
-
-        public void Dispose() {
-            if (Interlocked.Increment(ref m_disposed) == 1) {
-                Dispose(true);
-                GC.SuppressFinalize(this);
-            }
-        }
-
-        /// <summary>
-        /// Записывает сообщение об утечке объекта.
-        /// </summary>
-        protected virtual void ReportObjectLeaks() {
-            TraceLog.TraceWarning("The object is marked as disposable but isn't disposed properly: {0}", this);
-        }
-
-        ~Disposable() {
-            Dispose(false);
-            ReportObjectLeaks();
-        }
-    }
-}
\ No newline at end of file
--- a/Implab/DisposablePool.cs	Thu Feb 04 02:43:05 2016 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +0,0 @@
-using System;
-using Implab.Parallels;
-using System.Threading;
-using System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
-
-namespace Implab {
-    public abstract class DisposablePool<T> : IDisposable {
-        readonly int m_size;
-        readonly AsyncQueue<T> m_queue = new AsyncQueue<T>();
-
-        [SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")]
-        static readonly bool _isValueType = typeof(T).IsValueType;
-
-        bool m_disposed;
-
-        int m_count;
-
-        protected DisposablePool(int size) {
-            m_size = size;
-        }
-
-        protected DisposablePool() : this(Environment.ProcessorCount+1) {
-        }
-
-        public T Allocate() {
-            if (m_disposed)
-                throw new ObjectDisposedException(ToString());
-
-            T instance;
-            if (m_queue.TryDequeue(out instance)) {
-                Interlocked.Decrement(ref m_count);
-            } else {
-                instance = CreateInstance();
-                Debug.Assert(!Object.Equals(instance, default(T)) || _isValueType);
-            }
-            return instance;
-        }
-
-        protected abstract T CreateInstance();
-
-        protected virtual void CleanupInstance(T instance) {
-        }
-
-        public void Release(T instance) {
-            if ( Object.Equals(instance,default(T)) && !_isValueType)
-                return;
-
-            Thread.MemoryBarrier();
-            if (m_count < m_size && !m_disposed) {
-                Interlocked.Increment(ref m_count);
-
-                CleanupInstance(instance);
-
-                m_queue.Enqueue(instance);
-
-                // пока элемент возвращался в кеш, была начата операция освобождения всего кеша
-                // и возможно уже законцена, в таком случае следует извлечь элемент обратно и
-                // освободить его. Если операция освобождения кеша еще не заврешилась, то будет
-                // изъят и освобожден произвольный элемен, что не повлияет на ход всего процесса.
-                if (m_disposed && m_queue.TryDequeue(out instance) && instance is IDisposable)
-                    ((IDisposable)instance).Dispose() ;
-
-            } else {
-                if (instance is IDisposable)
-                    ((IDisposable)instance).Dispose();
-            }
-        }
-
-        protected virtual void Dispose(bool disposing) {
-            if (disposing) {
-                m_disposed = true;
-                T instance;
-                while (m_queue.TryDequeue(out instance))
-                    if (instance is IDisposable)
-                        ((IDisposable)instance).Dispose();
-            }
-        }
-
-        #region IDisposable implementation
-
-        public void Dispose() {
-            Dispose(true);
-            GC.SuppressFinalize(this);
-        }
-
-        #endregion
-    }
-}
-
--- a/Implab/IComponentContainer.cs	Thu Feb 04 02:43:05 2016 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-using System;
-
-namespace Implab {
-    public interface IComponentContainer {
-        void Add(IDisposable component);
-    }
-}
-
--- a/Implab/Implab.csproj	Thu Feb 04 02:43:05 2016 +0300
+++ b/Implab/Implab.csproj	Thu Feb 11 01:56:27 2016 +0300
@@ -75,7 +75,6 @@
     <Reference Include="mscorlib" />
   </ItemGroup>
   <ItemGroup>
-    <Compile Include="Component.cs" />
     <Compile Include="CustomEqualityComparer.cs" />
     <Compile Include="Diagnostics\ConsoleTraceListener.cs" />
     <Compile Include="Diagnostics\EventText.cs" />
@@ -85,7 +84,6 @@
     <Compile Include="Diagnostics\TraceLog.cs" />
     <Compile Include="Diagnostics\TraceEvent.cs" />
     <Compile Include="Diagnostics\TraceEventType.cs" />
-    <Compile Include="Disposable.cs" />
     <Compile Include="ICancellable.cs" />
     <Compile Include="IProgressHandler.cs" />
     <Compile Include="IProgressNotifier.cs" />
@@ -130,8 +128,6 @@
     <Compile Include="Parsing\StarToken.cs" />
     <Compile Include="Parsing\SymbolToken.cs" />
     <Compile Include="Parsing\Token.cs" />
-    <Compile Include="ServiceLocator.cs" />
-    <Compile Include="TaskController.cs" />
     <Compile Include="ProgressInitEventArgs.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Parallels\AsyncPool.cs" />
@@ -144,11 +140,7 @@
     <Compile Include="Diagnostics\LogEventArgs.cs" />
     <Compile Include="Diagnostics\LogEventArgsT.cs" />
     <Compile Include="Diagnostics\Extensions.cs" />
-    <Compile Include="IComponentContainer.cs" />
     <Compile Include="PromiseEventType.cs" />
-    <Compile Include="ComponentContainer.cs" />
-    <Compile Include="DisposablePool.cs" />
-    <Compile Include="ObjectPool.cs" />
     <Compile Include="Parallels\AsyncQueue.cs" />
     <Compile Include="PromiseT.cs" />
     <Compile Include="IDeferred.cs" />
@@ -180,6 +172,16 @@
     <Compile Include="SuccessPromiseT.cs" />
     <Compile Include="PromiseAwaiterT.cs" />
     <Compile Include="PromiseAwaiter.cs" />
+    <Compile Include="Components\ComponentContainer.cs" />
+    <Compile Include="Components\Disposable.cs" />
+    <Compile Include="Components\DisposablePool.cs" />
+    <Compile Include="Components\ObjectPool.cs" />
+    <Compile Include="Components\ServiceLocator.cs" />
+    <Compile Include="Components\IInitializable.cs" />
+    <Compile Include="TaskController.cs" />
+    <Compile Include="Components\App.cs" />
+    <Compile Include="Components\IRunnable.cs" />
+    <Compile Include="Components\ExecutionState.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ItemGroup />
@@ -252,4 +254,7 @@
       </Properties>
     </MonoDevelop>
   </ProjectExtensions>
+  <ItemGroup>
+    <Folder Include="Components\" />
+  </ItemGroup>
 </Project>
\ No newline at end of file
--- a/Implab/ObjectPool.cs	Thu Feb 04 02:43:05 2016 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-using Implab.Parallels;
-using System;
-using System.Threading;
-
-namespace Implab {
-    /// <summary>
-    /// Базовый класс для создания пулов объектов.
-    /// </summary>
-    /// <remarks>
-    /// <para>Пул объектов позволяет многократно использовать один и тотже объект,
-    /// что актуально для объектов, создание которых требует существенных ресурсов.
-    /// Пул объектов использует слабые ссылки, чтобы не препятствовать освобождению
-    /// ресурсов и создает новые объекты при необходимости.</para>
-    /// <para>
-    /// Наследники должны реализовывать метод <see cref="CreateInstance()"/> для создания
-    /// новых экземпляров.
-    /// </para>
-    /// <para>Пул поддерживает обращения сразу из нескольких потоков.</para>
-    /// </remarks>
-    public abstract class ObjectPool<T> where T : class {
-        readonly AsyncQueue<WeakReference> m_queue = new AsyncQueue<WeakReference>();
-        readonly int m_size;
-        int m_count = 0;
-
-        protected ObjectPool() : this(Environment.ProcessorCount+1) {
-
-        }
-
-        protected ObjectPool(int size) {
-            Safe.ArgumentInRange(size,1,size,"size");
-
-            m_size = size;
-        }
-
-        protected abstract T CreateInstance();
-
-        protected virtual void CleanupInstance(T instance) {
-        }
-
-        public T Allocate() {
-            WeakReference reference;
-            while (m_queue.TryDequeue(out reference)) {
-                Interlocked.Decrement(ref m_count);
-                object instance = reference.Target;
-                if (instance == null)
-                    continue;
-                return (T)instance;
-            }
-            return CreateInstance();
-        }
-
-        public void Release(T instance) {
-            if (m_count < m_size && instance != null) {
-                Interlocked.Increment(ref m_count);
-                CleanupInstance(instance);
-                m_queue.Enqueue(new WeakReference(instance));
-            }
-        }
-    }
-}
--- a/Implab/Parsing/Scanner.cs	Thu Feb 04 02:43:05 2016 +0300
+++ b/Implab/Parsing/Scanner.cs	Thu Feb 11 01:56:27 2016 +0300
@@ -2,9 +2,7 @@
 using System;
 using System.Collections.Generic;
 using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+using Implab.Components;
 
 namespace Implab.Parsing {
     /// <summary>
--- a/Implab/ServiceLocator.cs	Thu Feb 04 02:43:05 2016 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,248 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace Implab {
-    /// <summary>
-    /// Коллекция сервисов, позволяет регистрировать и получать сервисы.
-    /// </summary>
-    public class ServiceLocator: Disposable, IServiceLocator, IServiceProvider {
-        // запись о сервисе
-        struct ServiceEntry : IDisposable {
-            public object service; // сервис
-            public bool shared; // признак того, что сервис НЕ нужно освобождать
-            public Func<object> activator; // активатор сервиса при первом обращении
-            public Action<object> cleanup; // функция для очистки сервиса
-            public List<Type> associated; // ссылки на текущую запись
-            public Type origin; // ссылка на оригинальную запись о сервисе
-
-            #region IDisposable implementation
-
-            public void Dispose() {
-                if (shared)
-                    return;
-                if (cleanup != null) {
-                    if (service != null)
-                        cleanup(service);
-                } else
-                    Safe.Dispose(service);
-            }
-
-            #endregion
-        }
-
-        // словарь существующих сервисов
-        readonly Dictionary<Type, ServiceEntry> m_services = new Dictionary<Type,ServiceEntry>();
-
-        /// <summary>
-        /// Получает объект предоставляющий сервис <typeparamref name="T"/>.
-        /// </summary>
-        /// <typeparam name="T">Тип запрашиваемого сервиса</typeparam>
-        /// <returns>Объект, реализующий сервис</returns>
-        /// <exception cref="KeyNotFoundException">Сервис не зарегистрирован</exception>
-        public T GetService<T>() {
-            object result;
-            if (TryGetService(typeof(T), out result))
-                return (T)result;
-            throw new ApplicationException (String.Format ("{0} doesn't provide {1} service", this, typeof(T)));
-        }
-
-
-        /// <summary>
-        /// Пытается получить указанный сервис, в случае, если компонента не предоставляет требуемый сервис
-        /// не возникает исключений.
-        /// </summary>
-        /// <typeparam name="T">Тип требуемого сервиса.</typeparam>
-        /// <param name="service">Объект реализующий сервис, или <c>default(T)</c> если такового нет.</param>
-        /// <returns><c>true</c> - сервис найден, <c>false</c> - сервис не зарегистрирован.</returns>
-        public bool TryGetService<T>(out T service) {
-            object result;
-            if (TryGetService(typeof(T), out result)) {
-                service = (T)result;
-                return true;
-            }
-            service = default(T);
-            return false;
-        }
-
-        /// <summary>
-        /// Получает объект предоставляющий сервис <paramref name="serviceType"/>
-        /// </summary>
-        /// <param name="serviceType">Тип запрашиваемого сервиса</param>
-        /// <returns>Объект, реализующий сервис</returns>
-        /// <exception cref="KeyNotFoundException">Сервис не зарегистрирован</exception>
-		public object GetService(Type serviceType) {
-            object result;
-            if (TryGetService(serviceType, out result))
-                return result;
-			throw new ApplicationException (String.Format ("{0} doesn't provide {1} service", this, serviceType));
-		}
-
-		/// <summary>
-		/// Пытается получить требуемый сервис или совместимый с ним.
-		/// </summary>
-		/// <returns><c>true</c>, если сервис был найден, <c>false</c> в противном случае..</returns>
-		/// <param name="serviceType">Тип запрашиваемого сервиса.</param>
-		/// <param name="service">Искомый сервис.</param>
-		public virtual bool TryGetService(Type serviceType, out object service) {
-            Safe.ArgumentNotNull(serviceType, "serviceType");
-            AssertNotDisposed();
-
-            ServiceEntry se;
-            if (!m_services.TryGetValue(serviceType, out se)) {
-                // ищем ближайщий объект, реализующий нужный сервис
-                Type pt = null;
-                foreach (var t in m_services.Keys)
-                    if (serviceType.IsAssignableFrom(t) && (pt == null || t.IsAssignableFrom(pt)))
-                        pt = t;
-
-				if (pt == null) {
-					// нет нужного сервиса
-					service = null;
-					return false;
-				}
-
-                var pe = m_services[pt];
-
-                // найденная запись может ссылаться на оригинальную запись с сервисом
-                if(pe.origin != null) {
-                    pt = pe.origin;
-                    pe = m_services[pt];
-                }
-                    
-                // добавляем список с обратными ссылками
-                if (pe.associated == null)
-                    pe.associated = new List<Type>();
-
-                pe.associated.Add(serviceType);
-
-                // обновляем родительскую запись
-                m_services[pt] = pe;
-
-                // создаем запись со ссылкой
-                se = new ServiceEntry {
-                    service = pe.service,
-                    origin = pt,
-                    shared = true // предотвращаем множественные попытки освобождения
-                };
-
-                m_services[serviceType] = se;
-            }
-
-            // запись содержит в себе информацию о сервисе
-			if (se.service != null) {
-				service = se.service;
-				return true;
-			}
-
-            // текущая запись является ссылкой
-            if (se.origin != null) {
-                se.service = GetService(se.origin);
-                m_services[serviceType] = se;
-				service = se.service;
-				return true;
-            }
-
-            // текущая запись не является ссылкой и не имеет информации о сервисе
-            // она должна сожержать информацию об активации
-            if (se.activator != null) {
-                se.service = se.activator();
-
-                m_services[serviceType] = se;
-
-				service = se.service;
-				return true;
-            }
-
-			service = null;
-			return false;
-        }
-
-        /// <summary>
-        /// Регистрирует фабрику для активации сервиса по первому требованию.
-        /// </summary>
-        /// <typeparam name="T">Тип регистрируемого сервиса.</typeparam>
-        /// <param name="activator">Фабрика для создания/получения объекта, предоставляющего сервис.</param>
-        /// <param name = "cleanup">Метод для освобождения экземпляра сервиса, будет вызыван при освобождении сервис-локатора.</param>
-        /// <remarks>При освобождении сервис-локатора, сервисы полученные в результате активации также будут освобождены.</remarks>
-        public void Register<T>(Func<T> activator, Action<T> cleanup) {
-            Safe.ArgumentNotNull(activator, "activator");
-
-            AssertNotDisposed();
-
-            Unregister(typeof(T));
-            
-            var serviceEntry = new ServiceEntry();
-            serviceEntry.activator = () => activator();
-            if (cleanup != null)
-                serviceEntry.cleanup = instance => cleanup((T)instance);
-            m_services[typeof(T)] = serviceEntry;
-        }
-
-        public void Register<T>(Func<T> activator) {
-            Register(activator, null);
-        }
-
-        /// <summary>
-        /// Регистрирует объект, предоставляющий сервис.
-        /// </summary>
-        /// <typeparam name="T">Тип регистрируемого сервиса.</typeparam>
-        /// <param name="service">Объект, предоставляющий сервис.</param>
-        /// <exception cref="InvalidOperationException">Указанный сервис уже зарегистрирован.</exception>
-        /// <remarks>Сервис-локатором не управляет временем жизни объекта для зарегистрированного сервиса.</remarks>
-        public void Register<T>(T service) {
-            Register(service, true);
-        }
-
-        /// <summary>
-        /// Регистрирует объект, предоставляющий сервис. Повторная регистрация отменяет уже существующую.
-        /// </summary>
-        /// <typeparam name="T">Тип регистрируемого сервиса.</typeparam>
-        /// <param name="service">Объект, предоставляющий сервис.</param>
-        /// <param name="shared">Признак того, что объект является разделяемым и сервис-локатор не должен его освобождать.</param>
-        public void Register<T>(T service, bool shared) {
-            Safe.ArgumentNotNull(service, "service");
-
-            AssertNotDisposed();
-
-            Unregister(typeof(T));
-            
-            m_services[typeof(T)] = new ServiceEntry { service = service, shared = shared };
-        }
-
-        public void Unregister(Type serviceType) {
-            Safe.ArgumentNotNull(serviceType, "serviceType");
-
-            AssertNotDisposed();
-            
-            ServiceEntry se;
-            if (m_services.TryGetValue(serviceType, out se)) {
-                if (se.origin != null) {
-                    var pe = m_services[se.origin];
-                    pe.associated.Remove(serviceType);
-                }
-                // освобождаем ресурсы
-                se.Dispose();
-                m_services.Remove(serviceType);
-
-                // убираем связанные записи
-                if (se.associated != null)
-                    foreach (var item in se.associated)
-                        m_services.Remove(item);
-            }
-        }
-
-        /// <summary>
-        /// Освобождает зарегистрированные сервисы (которые требуется освобоить).
-        /// </summary>
-        /// <param name="disposing">Призанак того, что нужно освободить ресурсы.</param>
-        protected override void Dispose(bool disposing) {
-            if (disposing) {
-
-                foreach (var entry in m_services.Values)
-                    entry.Dispose();
-
-            }
-            base.Dispose(disposing);
-        }
-    }
-}
\ No newline at end of file