1437 lines · 56.7 KB · C#
RawDownload
//******************************************************************************************************//  AdapterLoader.cs - Gbtc////  Copyright © 2012, Grid Protection Alliance.  All Rights Reserved.////  Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See//  the NOTICE file distributed with this work for additional information regarding copyright ownership.//  The GPA licenses this file to you under the MIT License (MIT), the "License"; you may//  not use this file except in compliance with the License. You may obtain a copy of the License at:////      http://www.opensource.org/licenses/MIT////  Unless agreed to in writing, the subject software distributed under the License is distributed on an//  "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the//  License for the specific language governing permissions and limitations.////  Code Modification History://  ----------------------------------------------------------------------------------------------------//  07/20/2009 - Pinal C. Patel//       Generated original version of source code.//  08/06/2009 - Pinal C. Patel//       Modified Dispose(boolean) to iterate through the adapter collection correctly.//  09/14/2009 - Stephen C. Wills//       Added new header and license agreement.//  09/17/2009 - Pinal C. Patel//       Modified ProcessAdapter() to instantiate types with a default public constructor only.//  12/10/2009 - Pinal C. Patel//       Added new AdapterCreated event.//       Implemented IProvideStatus interface.//       Enhanced the implementation of Enabled property.//  09/23/2010 - Pinal C. Patel//       Added adapter isolation capability to allow for loading qualified adapters in separate //       application domain for isolated execution.//  10/01/2010 - Pinal C. Patel//       Added adapter monitoring capability to monitor the resource utilization of adapters.//  03/08/2011 - Pinal C. Patel//       Made IAdapter a requirement for using AdapterLoader for effectively managing serialized //       adapter instances.//       Added AdapterFileExtension and AdapterFileFormat properties to allow loading of binary and XML //       serialized adapter instances.//       Updated AdapterLoadException event to not provide the adapter's type since it might not be //       available when processing serialized adapter instances.//  04/05/2011 - Pinal C. Patel//       Modified deserializer class to use TypeName property instead of Type property to get the type //       of the object being deserialized when deserializing from an XML file.//  04/14/2011 - Pinal C. Patel//       Updated to use new serialization methods in GSF.Serialization class.//  05/11/2011 - Pinal C. Patel//       Implemented IPersistSettings interface.//       Changed the unit for AllowableProcessMemoryUsage and AllowableAdapterMemoryUsage properties //       from bytes to megabytes.//  09/21/2011 - J. Ritchie Carroll//       Added Mono implementation exception regions.//  11/23/2011 - J. Ritchie Carroll//       Modified to support buffer optimized ISupportBinaryImage.//  12/06/2011 - Pinal C. Patel//       Updated to instantiate a FileSystemWatcher object that watches for adapters only if needed //       to avoid a issue introduced in .NET 4.0 that causes memory leak.//  12/13/2012 - Starlynn Danyelle Gilliam//       Modified Header.//  01/29/2016 - Pinal C. Patel//       Fixed a bug in ProcessAdapter(string) method that was always replacing the first adapter//       in the adapter list instead of the adapter that was modified.//       Updated Deserializer.Deserialize() method to get an exclusive lock on the adapter file prior to//       processing it.////****************************************************************************************************** using System;using System.Collections.Generic;using System.Collections.ObjectModel;using System.Collections.Specialized;using System.Configuration;using System.Diagnostics;using System.IO;using System.Text;using System.Xml.Linq;using System.Xml.Serialization;using GSF.Collections;using GSF.Configuration;using GSF.IO;#if !MONOusing GSF.Units;using System.Threading;#endif namespace GSF.Adapters{    #region [ Enumerations ]     /// <summary>    /// Specifies the file format of the adapters to be loaded by the <see cref="AdapterLoader{T}"/>.    /// </summary>    public enum AdapterFileFormat    {        /// <summary>        /// Adapters are <see cref="Type"/>s inside <see cref="Assembly"/> files (DLLs).        /// </summary>        Assembly,        /// <summary>        /// Adapters are binary serialized instances persisted to files.        /// </summary>        SerializedBin,        /// <summary>        /// Adapters are XML serialized instances persisted to files.        /// </summary>        SerializedXml    }     #endregion     /// <summary>    /// Represents a generic loader of adapters.    /// </summary>    /// <typeparam name="T"><see cref="Type"/> of adapters to be loaded.</typeparam>    /// <example>    /// This example show how to use the <see cref="AdapterLoader{T}"/> to isolate adapters in separate <see cref="AppDomain"/>s and monitor their resource usage:    /// <code>    /// using System;    /// using System.Collections.Generic;    /// using System.Text;    /// using System.Threading;    /// using GSF;    /// using GSF.Adapters;    /// using GSF.Security.Cryptography;    ///     /// class Program    /// {    ///     static AdapterLoader&lt;PublishAdapterBase&gt; s_adapterLoader;    ///     ///     static void Main(string[] args)    ///     {    ///         // Enable app domain resource monitoring.    ///         AppDomain.MonitoringIsEnabled = true;    ///     ///         // Load adapters that mimic data publishing.    ///         s_adapterLoader = new AdapterLoader&lt;PublishAdapterBase&gt;();    ///         s_adapterLoader.IsolateAdapters = true;    ///         s_adapterLoader.MonitorAdapters = true;    ///         s_adapterLoader.AdapterFileExtension = "*.exe";    ///         s_adapterLoader.AllowableProcessMemoryUsage = 200;    ///         s_adapterLoader.AllowableProcessProcessorUsage = 50;    ///         s_adapterLoader.AllowableAdapterMemoryUsage = 100;    ///         s_adapterLoader.AllowableAdapterProcessorUsage = 25;    ///         s_adapterLoader.AdapterLoaded += OnAdapterLoaded;    ///         s_adapterLoader.AdapterUnloaded += OnAdapterUnloaded;    ///         s_adapterLoader.AdapterResourceUsageExceeded += OnAdapterResourceUsageExceeded;    ///         s_adapterLoader.Initialize();    ///     ///         // Shutdown.    ///         Console.ReadLine();    ///         s_adapterLoader.Dispose();    ///     }    ///     ///     static void OnAdapterLoaded(object sender, EventArgs&lt;PublishAdapterBase&gt; e)    ///     {    ///         Console.WriteLine("{0} has been loaded\r\n", e.Argument.GetType().Name);    ///     }    ///     ///     static void OnAdapterUnloaded(object sender, EventArgs&lt;PublishAdapterBase&gt; e)    ///     {    ///         Console.WriteLine("{0} has been unloaded\r\n", e.Argument.GetType().Name);    ///     }    ///     ///     static void OnAdapterResourceUsageExceeded(object sender, GSF.EventArgs&lt;PublishAdapterBase&gt; e)    ///     {    ///         Console.WriteLine("{0} status:", e.Argument.Name);    ///         Console.WriteLine(e.Argument.Status);    ///     ///         // Remove the adapter in order to reclaim the resources used by it.    ///         lock (s_adapterLoader.Adapters)    ///         {    ///             s_adapterLoader.Adapters.Remove(e.Argument);    ///         }    ///     }    /// }    ///     /// /// &lt;summary&gt;    /// /// Base adapter class.    /// /// &lt;/summary&gt;    /// public abstract class PublishAdapterBase : Adapter    /// {    ///     public PublishAdapterBase()    ///     {    ///         Data = new List&lt;byte[]&gt;();    ///     }    ///     ///     public List&lt;byte[]&gt; Data { get; set; }    ///     ///     public override void Initialize()    ///     {    ///         base.Initialize();    ///         new Thread(Publish).Start();    ///     }    ///     ///     protected abstract void Publish();    /// }    ///     /// /// &lt;summary&gt;    /// /// Adapter that does not manage memory well.    /// /// &lt;/summary&gt;    /// public class PublishAdapterA : PublishAdapterBase    /// {    ///     protected override void Publish()    ///     {    ///         while (true)    ///         {    ///             for (int i = 0; i &lt; 10000; i++)    ///             {    ///                 Data.Add(new byte[10]);    ///             }    ///             Thread.Sleep(100);    ///         }    ///     }    /// }    ///     /// /// &lt;summary&gt;    /// /// Adapter that uses the processor in excess.    /// /// &lt;/summary&gt;    /// public class PublishAdapterB : PublishAdapterBase    /// {    ///     protected override void Publish()    ///     {    ///         string text = string.Empty;    ///         System.Random random = new System.Random();    ///         while (true)    ///         {    ///             for (int i = 0; i &lt; 10; i++)    ///             {    ///                 for (int j = 0; j &lt; 4; j++)    ///                 {    ///                     text += (char)random.Next(256);    ///                 }    ///                 Data.Add(Encoding.ASCII.GetBytes(text.Encrypt("C1pH3r", CipherStrength.Aes256)).BlockCopy(0, 1));    ///             }    ///             Thread.Sleep(10);    ///         }    ///     }    /// }    /// </code>    /// </example>    /// <seealso cref="Adapter"/>    /// <seealso cref="IAdapter"/>    public class AdapterLoader<T> : ISupportLifecycle, IProvideStatus, IPersistSettings where T : class, IAdapter    {        #region [ Members ]         // Nested Types         private class Deserializer : MarshalByRefObject        {            public T Deserialize(string adapterFile, AdapterFileFormat adapterFormat)            {                // Attempt binary deserialization.                if (adapterFormat == AdapterFileFormat.SerializedBin)                {                    FilePath.WaitForReadLockExclusive(adapterFile);                    return Serialization.Deserialize<T>(File.ReadAllBytes(adapterFile), SerializationFormat.Binary);                }                 if (adapterFormat != AdapterFileFormat.SerializedXml)                    throw new NotSupportedException();                 // Attempt XML deserialization.                FilePath.WaitForReadLockExclusive(adapterFile);                XDocument xml = XDocument.Parse(File.ReadAllText(adapterFile));                 if ((object)xml.Root != null)                {                    XElement type = xml.Root.Element("TypeName");                     if ((object)type != null)                    {                        // Type element required for looking up the adapter's type.                        XmlSerializer serializer = new XmlSerializer(Type.GetType(type.Value));                         using (StringReader reader = new StringReader(xml.ToString()))                        {                            return (T)serializer.Deserialize(reader);                        }                    }                }                 throw new InvalidOperationException("TypeName element is missing in the XML");            }        }         // Constants         /// <summary>        /// Specifies the default value for the <see cref="AdapterDirectory"/> property.        /// </summary>        public const string DefaultAdapterDirectory = "";         /// <summary>        /// Specifies the default value for the <see cref="AdapterFileExtension"/> property.        /// </summary>        public const string DefaultAdapterFileExtension = "*.dll";         /// <summary>        /// Specifies the default value for the <see cref="AdapterFileFormat"/> property.        /// </summary>        public const AdapterFileFormat DefaultAdapterFileFormat = AdapterFileFormat.Assembly;         /// <summary>        /// Specifies the default value for the <see cref="WatchForAdapters"/> property.        /// </summary>        public const bool DefaultWatchForAdapters = true;         /// <summary>        /// Specifies the default value for the <see cref="IsolateAdapters"/> property.        /// </summary>        public const bool DefaultIsolateAdapters = false;         /// <summary>        /// Specifies the default value for the <see cref="MonitorAdapters"/> property.        /// </summary>        public const bool DefaultMonitorAdapters = false;         /// <summary>        /// Specifies the default value for the <see cref="AllowableProcessMemoryUsage"/> property        /// </summary>        public const double DefaultAllowableProcessMemoryUsage = 500;         /// <summary>        /// Specifies the default value for the <see cref="AllowableProcessProcessorUsage"/> property.        /// </summary>        public const double DefaultAllowableProcessProcessorUsage = 75;         /// <summary>        /// Specifies the default value for the <see cref="AllowableAdapterMemoryUsage"/> property.        /// </summary>        public const double DefaultAllowableAdapterMemoryUsage = 100;         /// <summary>        /// Specifies the default value for the <see cref="AllowableAdapterProcessorUsage"/> property.        /// </summary>        public const double DefaultAllowableAdapterProcessorUsage = 50;         // Events         /// <summary>        /// Occurs when a new adapter is found and instantiated.        /// </summary>        /// <remarks>        /// <see cref="EventArgs{T}.Argument"/> is the adapter that was created.        /// </remarks>        public event EventHandler<EventArgs<T>> AdapterCreated;         /// <summary>        /// Occurs when a new adapter is loaded to the <see cref="Adapters"/> list.        /// </summary>        /// <remarks>        /// <see cref="EventArgs{T}.Argument"/> is the adapter that was loaded.        /// </remarks>        public event EventHandler<EventArgs<T>> AdapterLoaded;         /// <summary>        /// Occurs when an existing adapter is unloaded from the <see cref="Adapters"/> list.        /// </summary>        /// <remarks>        /// <see cref="EventArgs{T}.Argument"/> is the adapter that was unloaded.        /// </remarks>        public event EventHandler<EventArgs<T>> AdapterUnloaded;         /// <summary>        /// Occurs when an adapter has exceeded either the <see cref="AllowableAdapterMemoryUsage"/> or <see cref="AllowableAdapterProcessorUsage"/>.        /// </summary>        /// <see cref="EventArgs{T}.Argument"/> is the adapter that exceeded the allowable system resource utilization.        public event EventHandler<EventArgs<T>> AdapterResourceUsageExceeded;         /// <summary>        /// Occurs when an <see cref="Exception"/> is encountered when loading an adapter.        /// </summary>        /// <remarks>        /// <see cref="EventArgs{T}.Argument"/> is the <see cref="Exception"/> encountered when loading the adapter.        /// </remarks>        public event EventHandler<EventArgs<Exception>> AdapterLoadException;         /// <summary>        /// Occurs when an <see cref="Exception"/> is encountered while executing a queued operation on one the <see cref="Adapters"/>.        /// </summary>        /// <remarks>        /// <see cref="EventArgs{T1,T2}.Argument1"/> is the adapter on which the operation was being executed.<br/>        /// <see cref="EventArgs{T1,T2}.Argument2"/> is the <see cref="Exception"/> encountered when executing an operation on the adapter.        /// </remarks>        public event EventHandler<EventArgs<T, Exception>> OperationExecutionException;         /// <summary>        /// Occurs when the class has been disposed.        /// </summary>        public event EventHandler Disposed;         // Fields        private string m_adapterDirectory;        private string m_adapterFileExtension;        private AdapterFileFormat m_adapterFileFormat;        private bool m_watchForAdapters;        private bool m_isolateAdapters;        private bool m_monitorAdapters;        private double m_allowableProcessMemoryUsage;        private double m_allowableProcessProcessorUsage;        private double m_allowableAdapterMemoryUsage;        private double m_allowableAdapterProcessorUsage;        private bool m_persistSettings;        private string m_settingsCategory;        private readonly ObservableCollection<T> m_adapters;        private SafeFileWatcher m_adapterWatcher;        private readonly AsyncQueue<object> m_operationQueue;        private readonly Dictionary<Type, bool> m_enabledStates;        private bool m_enabled;        private bool m_disposed;        private bool m_initialized;#if !MONO        private Thread m_adapterMonitoringThread;#endif         #endregion         #region [ Constructors ]         /// <summary>        /// Initializes a new instance of the <see cref="AdapterLoader{T}"/> class.        /// </summary>        public AdapterLoader()        {            m_adapterDirectory = DefaultAdapterDirectory;            m_adapterFileExtension = DefaultAdapterFileExtension;            m_adapterFileFormat = DefaultAdapterFileFormat;            m_watchForAdapters = DefaultWatchForAdapters;            m_isolateAdapters = DefaultIsolateAdapters;            m_monitorAdapters = DefaultMonitorAdapters;            m_allowableProcessMemoryUsage = DefaultAllowableProcessMemoryUsage;            m_allowableProcessProcessorUsage = DefaultAllowableProcessProcessorUsage;            m_allowableAdapterMemoryUsage = DefaultAllowableAdapterMemoryUsage;            m_allowableAdapterProcessorUsage = DefaultAllowableAdapterProcessorUsage;            m_settingsCategory = GetType().Name;            m_adapters = new ObservableCollection<T>();            m_adapters.CollectionChanged += Adapters_CollectionChanged;            m_operationQueue = new AsyncQueue<object>();            m_enabledStates = new Dictionary<Type, bool>();             m_operationQueue.ProcessItemFunction = ExecuteOperation;        }         /// <summary>        /// Releases the unmanaged resources before the <see cref="AdapterLoader{T}"/> is reclaimed by <see cref="GC"/>.        /// </summary>        ~AdapterLoader()        {            Dispose(false);        }         #endregion         #region [ Properties ]         /// <summary>        /// Gets or sets the directory where <see cref="Adapters"/> are located.        /// </summary>        /// <remarks>        /// When an empty string is assigned to <see cref="AdapterDirectory"/>, <see cref="Adapters"/> are loaded from the directory where application is executing.        /// </remarks>        /// <exception cref="ArgumentNullException">The value being assigned is a null string.</exception>        public string AdapterDirectory        {            get            {                return m_adapterDirectory;            }            set            {                if ((object)value == null)                    throw new ArgumentNullException(nameof(value));                 m_adapterDirectory = value;            }        }         /// <summary>        /// Gets or sets the file extension of the <see cref="Adapters"/>.        /// </summary>        /// <exception cref="ArgumentNullException">The value being set is a null or empty string.</exception>        public string AdapterFileExtension        {            get            {                return m_adapterFileExtension;            }            set            {                if (string.IsNullOrEmpty(value))                    throw new ArgumentNullException(nameof(value));                 m_adapterFileExtension = value;            }        }         /// <summary>        /// Gets or sets the file format of the <see cref="Adapters"/>.

Lines 1–500 of 1437.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t