//******************************************************************************************************// 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<PublishAdapterBase> 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<PublishAdapterBase>(); /// 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<PublishAdapterBase> e) /// { /// Console.WriteLine("{0} has been loaded\r\n", e.Argument.GetType().Name); /// } /// /// static void OnAdapterUnloaded(object sender, EventArgs<PublishAdapterBase> e) /// { /// Console.WriteLine("{0} has been unloaded\r\n", e.Argument.GetType().Name); /// } /// /// static void OnAdapterResourceUsageExceeded(object sender, GSF.EventArgs<PublishAdapterBase> 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); /// } /// } /// } /// /// /// <summary> /// /// Base adapter class. /// /// </summary> /// public abstract class PublishAdapterBase : Adapter /// { /// public PublishAdapterBase() /// { /// Data = new List<byte[]>(); /// } /// /// public List<byte[]> Data { get; set; } /// /// public override void Initialize() /// { /// base.Initialize(); /// new Thread(Publish).Start(); /// } /// /// protected abstract void Publish(); /// } /// /// /// <summary> /// /// Adapter that does not manage memory well. /// /// </summary> /// public class PublishAdapterA : PublishAdapterBase /// { /// protected override void Publish() /// { /// while (true) /// { /// for (int i = 0; i < 10000; i++) /// { /// Data.Add(new byte[10]); /// } /// Thread.Sleep(100); /// } /// } /// } /// /// /// <summary> /// /// Adapter that uses the processor in excess. /// /// </summary> /// 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 < 10; i++) /// { /// for (int j = 0; j < 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. Load more
//****************************************************************************************************** // 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 !MONO using 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<PublishAdapterBase> 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<PublishAdapterBase>(); /// 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<PublishAdapterBase> e) /// { /// Console.WriteLine("{0} has been loaded\r\n", e.Argument.GetType().Name); /// } /// /// static void OnAdapterUnloaded(object sender, EventArgs<PublishAdapterBase> e) /// { /// Console.WriteLine("{0} has been unloaded\r\n", e.Argument.GetType().Name); /// } /// /// static void OnAdapterResourceUsageExceeded(object sender, GSF.EventArgs<PublishAdapterBase> 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); /// } /// } /// } /// /// /// <summary> /// /// Base adapter class. /// /// </summary> /// public abstract class PublishAdapterBase : Adapter /// { /// public PublishAdapterBase() /// { /// Data = new List<byte[]>(); /// } /// /// public List<byte[]> Data { get; set; } /// /// public override void Initialize() /// { /// base.Initialize(); /// new Thread(Publish).Start(); /// } /// /// protected abstract void Publish(); /// } /// /// /// <summary> /// /// Adapter that does not manage memory well. /// /// </summary> /// public class PublishAdapterA : PublishAdapterBase /// { /// protected override void Publish() /// { /// while (true) /// { /// for (int i = 0; i < 10000; i++) /// { /// Data.Add(new byte[10]); /// } /// Thread.Sleep(100); /// } /// } /// } /// /// /// <summary> /// /// Adapter that uses the processor in excess. /// /// </summary> /// 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 < 10; i++) /// { /// for (int j = 0; j < 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"/>.