//******************************************************************************************************// IaonSession.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:// ----------------------------------------------------------------------------------------------------// 08/23/2011 - J. Ritchie Carroll// Generated original version of source code.// 12/20/2012 - Starlynn Danyelle Gilliam// Modified Header.////****************************************************************************************************** using System;using System.Data;using System.Linq;using System.Text;using GSF.Annotations;using GSF.Collections;using GSF.Configuration;using GSF.Diagnostics;using System.Collections.Generic; // ReSharper disable InconsistentlySynchronizedFieldnamespace GSF.TimeSeries.Adapters{ /// <summary> /// Represents a new Input, Action, Output interface session. /// </summary> public class IaonSession : IProvideStatus, IDisposable { #region [ Members ] // Events /// <summary> /// Provides status messages to consumer. /// </summary> /// <remarks> /// <see cref="EventArgs{T1,T2}.Argument1"/> is the new status message.<br/> /// <see cref="EventArgs{T1,T2}.Argument2"/> is the message <see cref="UpdateType"/>. /// </remarks> public event EventHandler<EventArgs<string, UpdateType>> StatusMessage; /// <summary> /// Event is raised when there is an exception encountered while processing. /// </summary> /// <remarks> /// <see cref="EventArgs{T}.Argument"/> is the exception that was thrown. /// </remarks> public event EventHandler<EventArgs<Exception>> ProcessException; /// <summary> /// Event is raised when <see cref="IAdapter.InputMeasurementKeys"/> are updated. /// </summary> public event EventHandler InputMeasurementKeysUpdated; /// <summary> /// Event is raised when <see cref="IAdapter.OutputMeasurements"/> are updated. /// </summary> public event EventHandler OutputMeasurementsUpdated; /// <summary> /// Event is raised when adapter is aware of a configuration change. /// </summary> public event EventHandler ConfigurationChanged; /// <summary> /// Event is raised every five seconds allowing consumer to track current number of unpublished seconds of data in the queue. /// </summary> /// <remarks> /// <see cref="EventArgs{T}.Argument"/> is the total number of unpublished seconds of data. /// </remarks> public event EventHandler<EventArgs<int>> UnpublishedSamples; /// <summary> /// Event is raised every five seconds allowing host to track total number of unprocessed measurements. /// </summary> /// <remarks> /// <para> /// Each <see cref="IOutputAdapter"/> implementation reports its current queue size of unprocessed /// measurements so that if queue size reaches an unhealthy threshold, host can take evasive action. /// </para> /// <para> /// <see cref="EventArgs{T}.Argument"/> is total number of unprocessed measurements. /// </para> /// </remarks> public event EventHandler<EventArgs<int>> UnprocessedMeasurements; /// <summary> /// Indicates to the host that processing for one of the input adapters has completed. /// </summary> /// <remarks> /// This event is expected to only be raised when an input adapter has been designed to process /// a finite amount of data, e.g., reading a historical range of data during temporal processing. /// </remarks> public event EventHandler ProcessingComplete; /// <summary> /// Event is raised when this <see cref="AdapterCollectionBase{T}"/> is disposed or an <see cref="IAdapter"/> in the collection is disposed. /// </summary> public event EventHandler Disposed; // Fields private Guid m_nodeID; private RoutingTables m_routingTables; private AllAdaptersCollection m_allAdapters; private FilterAdapterCollection m_filterAdapters; private InputAdapterCollection m_inputAdapters; private ActionAdapterCollection m_actionAdapters; private OutputAdapterCollection m_outputAdapters; private MeasurementKey[] m_inputMeasurementKeysRestriction; private readonly int m_measurementWarningThreshold; private readonly int m_measurementDumpingThreshold; private readonly int m_defaultSampleSizeWarningThreshold; private string m_name; private bool m_disposed; #endregion #region [ Constructors ] /// <summary> /// Creates a new <see cref="IaonSession"/>. /// </summary> public IaonSession() { ConfigurationFile configFile = ConfigurationFile.Current; // Initialize system settings CategorizedSettingsElementCollection systemSettings = configFile.Settings["systemSettings"]; systemSettings.Add("NodeID", Guid.NewGuid().ToString(), "Unique Node ID"); m_nodeID = systemSettings["NodeID"].ValueAs<Guid>(); // Initialize threshold settings CategorizedSettingsElementCollection thresholdSettings = configFile.Settings["thresholdSettings"]; thresholdSettings.Add("MeasurementWarningThreshold", "100000", "Number of unarchived measurements allowed in any output adapter queue before displaying a warning message"); thresholdSettings.Add("MeasurementDumpingThreshold", "500000", "Number of unarchived measurements allowed in any output adapter queue before taking evasive action and dumping data"); thresholdSettings.Add("DefaultSampleSizeWarningThreshold", "10", "Default number of unpublished samples (in seconds) allowed in any action adapter queue before displaying a warning message"); m_measurementWarningThreshold = thresholdSettings["MeasurementWarningThreshold"].ValueAsInt32(); m_measurementDumpingThreshold = thresholdSettings["MeasurementDumpingThreshold"].ValueAsInt32(); m_defaultSampleSizeWarningThreshold = thresholdSettings["DefaultSampleSizeWarningThreshold"].ValueAsInt32(); using (Logger.AppendStackMessages("HostAdapter","IaonSession")) { // Create a new set of routing tables switch (OptimizationOptions.DefaultRoutingMethod) { case OptimizationOptions.RoutingMethod.HighLatencyLowCpu: m_routingTables = new RoutingTables(new RouteMappingHighLatencyLowCpu()); break; default: m_routingTables = new RoutingTables(); break; } } m_routingTables.StatusMessage += m_routingTables_StatusMessage; m_routingTables.ProcessException += m_routingTables_ProcessException; // Create a collection to manage all input, action and output adapter collections as a unit m_allAdapters = new AllAdaptersCollection(); // Attach to common adapter events m_allAdapters.StatusMessage += StatusMessageHandler; m_allAdapters.ProcessException += ProcessExceptionHandler; m_allAdapters.InputMeasurementKeysUpdated += InputMeasurementKeysUpdatedHandler; m_allAdapters.OutputMeasurementsUpdated += OutputMeasurementsUpdatedHandler; m_allAdapters.ConfigurationChanged += ConfigurationChangedHandler; m_allAdapters.Disposed += DisposedHandler; // Create filter adapters collection m_filterAdapters = new FilterAdapterCollection(); // Create input adapters collection m_inputAdapters = new InputAdapterCollection(); m_inputAdapters.NewMeasurements += NewMeasurementsHandler; m_inputAdapters.ProcessingComplete += ProcessingCompleteHandler; // Create action adapters collection m_actionAdapters = new ActionAdapterCollection(); m_actionAdapters.NewMeasurements += NewMeasurementsHandler; m_actionAdapters.UnpublishedSamples += UnpublishedSamplesHandler; m_actionAdapters.RequestTemporalSupport += RequestTemporalSupportHandler; // Create output adapters collection m_outputAdapters = new OutputAdapterCollection(); m_outputAdapters.UnprocessedMeasurements += UnprocessedMeasurementsHandler; // Associate adapter collections with routing tables m_routingTables.InputAdapters = m_inputAdapters; m_routingTables.ActionAdapters = m_actionAdapters; m_routingTables.OutputAdapters = m_outputAdapters; // We group these adapters such that they are initialized in the following order: output, filter, input, action. // This is done so that the archival capabilities will be setup before we start receiving input and the input // data will be flowing before any actions get established for the input - at least generally. m_allAdapters.Add(m_outputAdapters); m_allAdapters.Add(m_filterAdapters); m_allAdapters.Add(m_inputAdapters); m_allAdapters.Add(m_actionAdapters); } /// <summary> /// Releases the unmanaged resources before the <see cref="IaonSession"/> object is reclaimed by <see cref="GC"/>. /// </summary> ~IaonSession() => Dispose(false); #endregion #region [ Properties ] /// <summary> /// Gets the all adapters collection for this <see cref="IaonSession"/>. /// </summary> public virtual AllAdaptersCollection AllAdapters => m_allAdapters; /// <summary> /// Gets the filter adapter collection for this <see cref="IaonSession"/>. /// </summary> public virtual FilterAdapterCollection FilterAdapters => m_filterAdapters; /// <summary> /// Gets the input adapter collection for this <see cref="IaonSession"/>. /// </summary> public virtual InputAdapterCollection InputAdapters => m_inputAdapters; /// <summary> /// Gets the action adapter collection for this <see cref="IaonSession"/>. /// </summary> public virtual ActionAdapterCollection ActionAdapters => m_actionAdapters; /// <summary> /// Gets the output adapter collection for this <see cref="IaonSession"/>. /// </summary> public virtual OutputAdapterCollection OutputAdapters => m_outputAdapters; /// <summary> /// Gets the routing tables for this <see cref="IaonSession"/>. /// </summary> public virtual RoutingTables RoutingTables => m_routingTables; /// <summary> /// Gets or sets a routing table restriction for a collection of input measurement keys. /// </summary> public virtual MeasurementKey[] InputMeasurementKeysRestriction { get => m_inputMeasurementKeysRestriction; set => m_inputMeasurementKeysRestriction = value; } /// <summary> /// Gets or sets the configuration <see cref="DataSet"/> for this <see cref="IaonSession"/>. /// </summary> public virtual DataSet DataSource { get => m_allAdapters.DataSource; set => m_allAdapters.DataSource = value; } /// <summary> /// Gets or sets the <see cref="Guid"/> node ID for this <see cref="IaonSession"/>. /// </summary> public virtual Guid NodeID { get => m_nodeID; set => m_nodeID = value; } /// <summary> /// Gets name assigned to this <see cref="IaonSession"/>, if any. /// </summary> public virtual string Name { get => m_name.ToNonNullString(); set => m_name = value; } /// <summary> /// Gets the combined status of the adapters in this <see cref="IaonSession"/>. /// </summary> public virtual string Status { get { StringBuilder status = new StringBuilder(); status.AppendLine(); status.AppendLine(">> Filter Adapters:"); status.AppendLine(); if (!(m_filterAdapters is null)) status.AppendLine(m_filterAdapters.Status); status.AppendLine(); status.AppendLine(">> Input Adapters:"); status.AppendLine(); if (!(m_inputAdapters is null)) status.AppendLine(m_inputAdapters.Status); status.AppendLine(); status.AppendLine(">> Action Adapters:"); status.AppendLine(); if (!(m_actionAdapters is null)) status.AppendLine(m_actionAdapters.Status); status.AppendLine(); status.AppendLine(">> Output Adapters:"); status.AppendLine(); if (!(m_outputAdapters is null)) status.AppendLine(m_outputAdapters.Status); return status.ToString(); } } #endregion #region [ Methods ] /// <summary> /// Releases all the resources used by the <see cref="IaonSession"/> object. /// </summary> public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// <summary> /// Releases the unmanaged resources used by the <see cref="IaonSession"/> object and optionally releases the managed resources. /// </summary> /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param> protected virtual void Dispose(bool disposing) { if (m_disposed) return; try { if (!disposing) return; DataSet dataSource = DataSource; // Dispose filter adapters collection if (!(m_filterAdapters is null)) { m_filterAdapters.Stop(); m_filterAdapters.Dispose(); } m_filterAdapters = null; // Dispose input adapters collection if (!(m_inputAdapters is null)) { m_inputAdapters.Stop(); m_inputAdapters.NewMeasurements -= NewMeasurementsHandler; m_inputAdapters.ProcessingComplete -= ProcessingCompleteHandler; m_inputAdapters.Dispose(); } m_inputAdapters = null; // Dispose action adapters collection if (!(m_actionAdapters is null)) { m_actionAdapters.Stop(); m_actionAdapters.NewMeasurements -= NewMeasurementsHandler; m_actionAdapters.UnpublishedSamples -= UnpublishedSamplesHandler; m_actionAdapters.RequestTemporalSupport -= RequestTemporalSupportHandler; m_actionAdapters.Dispose(); } m_actionAdapters = null; // Dispose output adapters collection if (!(m_outputAdapters is null)) { m_outputAdapters.Stop(); m_outputAdapters.UnprocessedMeasurements -= UnprocessedMeasurementsHandler; m_outputAdapters.Dispose(); } m_outputAdapters = null; // Dispose all adapters collection if (!(m_allAdapters is null)) { m_allAdapters.StatusMessage -= StatusMessageHandler; m_allAdapters.ProcessException -= ProcessExceptionHandler; m_allAdapters.InputMeasurementKeysUpdated -= InputMeasurementKeysUpdatedHandler; m_allAdapters.OutputMeasurementsUpdated -= OutputMeasurementsUpdatedHandler; m_allAdapters.ConfigurationChanged -= ConfigurationChangedHandler; m_allAdapters.Disposed -= DisposedHandler; m_allAdapters.Dispose(); } m_allAdapters = null; // Dispose of routing tables if (!(m_routingTables is null)) { m_routingTables.StatusMessage -= m_routingTables_StatusMessage; m_routingTables.ProcessException -= m_routingTables_ProcessException; m_routingTables.Dispose(); } m_routingTables = null; dataSource?.Dispose(); } finally { m_disposed = true; // Prevent duplicate dispose. Disposed?.Invoke(this, EventArgs.Empty); } } /// <summary> /// Initialize and start adapters. /// </summary> /// <param name="autoStart">Sets flag that determines if adapters should be automatically started.</param> public virtual void Initialize(bool autoStart = true) { // Initialize all adapters m_allAdapters.Initialize(); // Start all adapters if they // haven't started already if (autoStart) m_allAdapters.Start(); } /// <summary> /// Gets flag that determines if temporal processing is supported in this <see cref="IaonSession"/>. /// </summary> /// <param name="collection">Name of collection over which to check support (e.g., "InputAdapters"); or <c>null</c> for all collections.</param> /// <returns>Flag that determines if temporal processing is supported in this <see cref="IaonSession"/>.</returns> public virtual bool TemporalProcessingSupportExists(string collection = null) { try { DataTable temporalSupport = m_allAdapters?.DataSource?.Tables["TemporalSupport"]; if (temporalSupport is null) return false; if (string.IsNullOrWhiteSpace(collection)) return temporalSupport.Rows.Count > 0; return temporalSupport.Select($"Source = '{collection}'").Length > 0; } catch (Exception ex) { Logger.SwallowException(ex, "Ignored Exception", "Failures are non-catastrophic and should only result in false."); return false; } } /// <summary> /// Gets derived name of specified object. /// </summary> /// <param name="sender">Sending object from which to derive name.</param> /// <returns>Derived name of specified object.</returns> public virtual string GetDerivedName(object sender) { string name = null; switch (sender) { case IProvideStatus statusProvider: name = statusProvider.Name; break; case string nameValue: name = nameValue; break; } if (string.IsNullOrWhiteSpace(name)) name = sender.GetType().Name; if (!string.IsNullOrWhiteSpace(m_name)) name += "#" + m_name; return name; } Lines 1–500 of 909. Load more
//****************************************************************************************************** // IaonSession.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: // ---------------------------------------------------------------------------------------------------- // 08/23/2011 - J. Ritchie Carroll // Generated original version of source code. // 12/20/2012 - Starlynn Danyelle Gilliam // Modified Header. // //****************************************************************************************************** using System; using System.Data; using System.Linq; using System.Text; using GSF.Annotations; using GSF.Collections; using GSF.Configuration; using GSF.Diagnostics; using System.Collections.Generic; // ReSharper disable InconsistentlySynchronizedField namespace GSF.TimeSeries.Adapters { /// <summary> /// Represents a new Input, Action, Output interface session. /// </summary> public class IaonSession : IProvideStatus, IDisposable { #region [ Members ] // Events /// <summary> /// Provides status messages to consumer. /// </summary> /// <remarks> /// <see cref="EventArgs{T1,T2}.Argument1"/> is the new status message.<br/> /// <see cref="EventArgs{T1,T2}.Argument2"/> is the message <see cref="UpdateType"/>. /// </remarks> public event EventHandler<EventArgs<string, UpdateType>> StatusMessage; /// <summary> /// Event is raised when there is an exception encountered while processing. /// </summary> /// <remarks> /// <see cref="EventArgs{T}.Argument"/> is the exception that was thrown. /// </remarks> public event EventHandler<EventArgs<Exception>> ProcessException; /// <summary> /// Event is raised when <see cref="IAdapter.InputMeasurementKeys"/> are updated. /// </summary> public event EventHandler InputMeasurementKeysUpdated; /// <summary> /// Event is raised when <see cref="IAdapter.OutputMeasurements"/> are updated. /// </summary> public event EventHandler OutputMeasurementsUpdated; /// <summary> /// Event is raised when adapter is aware of a configuration change. /// </summary> public event EventHandler ConfigurationChanged; /// <summary> /// Event is raised every five seconds allowing consumer to track current number of unpublished seconds of data in the queue. /// </summary> /// <remarks> /// <see cref="EventArgs{T}.Argument"/> is the total number of unpublished seconds of data. /// </remarks> public event EventHandler<EventArgs<int>> UnpublishedSamples; /// <summary> /// Event is raised every five seconds allowing host to track total number of unprocessed measurements. /// </summary> /// <remarks> /// <para> /// Each <see cref="IOutputAdapter"/> implementation reports its current queue size of unprocessed /// measurements so that if queue size reaches an unhealthy threshold, host can take evasive action. /// </para> /// <para> /// <see cref="EventArgs{T}.Argument"/> is total number of unprocessed measurements. /// </para> /// </remarks> public event EventHandler<EventArgs<int>> UnprocessedMeasurements; /// <summary> /// Indicates to the host that processing for one of the input adapters has completed. /// </summary> /// <remarks> /// This event is expected to only be raised when an input adapter has been designed to process /// a finite amount of data, e.g., reading a historical range of data during temporal processing. /// </remarks> public event EventHandler ProcessingComplete; /// <summary> /// Event is raised when this <see cref="AdapterCollectionBase{T}"/> is disposed or an <see cref="IAdapter"/> in the collection is disposed. /// </summary> public event EventHandler Disposed; // Fields private Guid m_nodeID; private RoutingTables m_routingTables; private AllAdaptersCollection m_allAdapters; private FilterAdapterCollection m_filterAdapters; private InputAdapterCollection m_inputAdapters; private ActionAdapterCollection m_actionAdapters; private OutputAdapterCollection m_outputAdapters; private MeasurementKey[] m_inputMeasurementKeysRestriction; private readonly int m_measurementWarningThreshold; private readonly int m_measurementDumpingThreshold; private readonly int m_defaultSampleSizeWarningThreshold; private string m_name; private bool m_disposed; #endregion #region [ Constructors ] /// <summary> /// Creates a new <see cref="IaonSession"/>. /// </summary> public IaonSession() { ConfigurationFile configFile = ConfigurationFile.Current; // Initialize system settings CategorizedSettingsElementCollection systemSettings = configFile.Settings["systemSettings"]; systemSettings.Add("NodeID", Guid.NewGuid().ToString(), "Unique Node ID"); m_nodeID = systemSettings["NodeID"].ValueAs<Guid>(); // Initialize threshold settings CategorizedSettingsElementCollection thresholdSettings = configFile.Settings["thresholdSettings"]; thresholdSettings.Add("MeasurementWarningThreshold", "100000", "Number of unarchived measurements allowed in any output adapter queue before displaying a warning message"); thresholdSettings.Add("MeasurementDumpingThreshold", "500000", "Number of unarchived measurements allowed in any output adapter queue before taking evasive action and dumping data"); thresholdSettings.Add("DefaultSampleSizeWarningThreshold", "10", "Default number of unpublished samples (in seconds) allowed in any action adapter queue before displaying a warning message"); m_measurementWarningThreshold = thresholdSettings["MeasurementWarningThreshold"].ValueAsInt32(); m_measurementDumpingThreshold = thresholdSettings["MeasurementDumpingThreshold"].ValueAsInt32(); m_defaultSampleSizeWarningThreshold = thresholdSettings["DefaultSampleSizeWarningThreshold"].ValueAsInt32(); using (Logger.AppendStackMessages("HostAdapter","IaonSession")) { // Create a new set of routing tables switch (OptimizationOptions.DefaultRoutingMethod) { case OptimizationOptions.RoutingMethod.HighLatencyLowCpu: m_routingTables = new RoutingTables(new RouteMappingHighLatencyLowCpu()); break; default: m_routingTables = new RoutingTables(); break; } } m_routingTables.StatusMessage += m_routingTables_StatusMessage; m_routingTables.ProcessException += m_routingTables_ProcessException; // Create a collection to manage all input, action and output adapter collections as a unit m_allAdapters = new AllAdaptersCollection(); // Attach to common adapter events m_allAdapters.StatusMessage += StatusMessageHandler; m_allAdapters.ProcessException += ProcessExceptionHandler; m_allAdapters.InputMeasurementKeysUpdated += InputMeasurementKeysUpdatedHandler; m_allAdapters.OutputMeasurementsUpdated += OutputMeasurementsUpdatedHandler; m_allAdapters.ConfigurationChanged += ConfigurationChangedHandler; m_allAdapters.Disposed += DisposedHandler; // Create filter adapters collection m_filterAdapters = new FilterAdapterCollection(); // Create input adapters collection m_inputAdapters = new InputAdapterCollection(); m_inputAdapters.NewMeasurements += NewMeasurementsHandler; m_inputAdapters.ProcessingComplete += ProcessingCompleteHandler; // Create action adapters collection m_actionAdapters = new ActionAdapterCollection(); m_actionAdapters.NewMeasurements += NewMeasurementsHandler; m_actionAdapters.UnpublishedSamples += UnpublishedSamplesHandler; m_actionAdapters.RequestTemporalSupport += RequestTemporalSupportHandler; // Create output adapters collection m_outputAdapters = new OutputAdapterCollection(); m_outputAdapters.UnprocessedMeasurements += UnprocessedMeasurementsHandler; // Associate adapter collections with routing tables m_routingTables.InputAdapters = m_inputAdapters; m_routingTables.ActionAdapters = m_actionAdapters; m_routingTables.OutputAdapters = m_outputAdapters; // We group these adapters such that they are initialized in the following order: output, filter, input, action. // This is done so that the archival capabilities will be setup before we start receiving input and the input // data will be flowing before any actions get established for the input - at least generally. m_allAdapters.Add(m_outputAdapters); m_allAdapters.Add(m_filterAdapters); m_allAdapters.Add(m_inputAdapters); m_allAdapters.Add(m_actionAdapters); } /// <summary> /// Releases the unmanaged resources before the <see cref="IaonSession"/> object is reclaimed by <see cref="GC"/>. /// </summary> ~IaonSession() => Dispose(false); #endregion #region [ Properties ] /// <summary> /// Gets the all adapters collection for this <see cref="IaonSession"/>. /// </summary> public virtual AllAdaptersCollection AllAdapters => m_allAdapters; /// <summary> /// Gets the filter adapter collection for this <see cref="IaonSession"/>. /// </summary> public virtual FilterAdapterCollection FilterAdapters => m_filterAdapters; /// <summary> /// Gets the input adapter collection for this <see cref="IaonSession"/>. /// </summary> public virtual InputAdapterCollection InputAdapters => m_inputAdapters; /// <summary> /// Gets the action adapter collection for this <see cref="IaonSession"/>. /// </summary> public virtual ActionAdapterCollection ActionAdapters => m_actionAdapters; /// <summary> /// Gets the output adapter collection for this <see cref="IaonSession"/>. /// </summary> public virtual OutputAdapterCollection OutputAdapters => m_outputAdapters; /// <summary> /// Gets the routing tables for this <see cref="IaonSession"/>. /// </summary> public virtual RoutingTables RoutingTables => m_routingTables; /// <summary> /// Gets or sets a routing table restriction for a collection of input measurement keys. /// </summary> public virtual MeasurementKey[] InputMeasurementKeysRestriction { get => m_inputMeasurementKeysRestriction; set => m_inputMeasurementKeysRestriction = value; } /// <summary> /// Gets or sets the configuration <see cref="DataSet"/> for this <see cref="IaonSession"/>. /// </summary> public virtual DataSet DataSource { get => m_allAdapters.DataSource; set => m_allAdapters.DataSource = value; } /// <summary> /// Gets or sets the <see cref="Guid"/> node ID for this <see cref="IaonSession"/>. /// </summary> public virtual Guid NodeID { get => m_nodeID; set => m_nodeID = value; } /// <summary> /// Gets name assigned to this <see cref="IaonSession"/>, if any. /// </summary> public virtual string Name { get => m_name.ToNonNullString(); set => m_name = value; } /// <summary> /// Gets the combined status of the adapters in this <see cref="IaonSession"/>. /// </summary> public virtual string Status { get { StringBuilder status = new StringBuilder(); status.AppendLine(); status.AppendLine(">> Filter Adapters:"); status.AppendLine(); if (!(m_filterAdapters is null)) status.AppendLine(m_filterAdapters.Status); status.AppendLine(); status.AppendLine(">> Input Adapters:"); status.AppendLine(); if (!(m_inputAdapters is null)) status.AppendLine(m_inputAdapters.Status); status.AppendLine(); status.AppendLine(">> Action Adapters:"); status.AppendLine(); if (!(m_actionAdapters is null)) status.AppendLine(m_actionAdapters.Status); status.AppendLine(); status.AppendLine(">> Output Adapters:"); status.AppendLine(); if (!(m_outputAdapters is null)) status.AppendLine(m_outputAdapters.Status); return status.ToString(); } } #endregion #region [ Methods ] /// <summary> /// Releases all the resources used by the <see cref="IaonSession"/> object. /// </summary> public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// <summary> /// Releases the unmanaged resources used by the <see cref="IaonSession"/> object and optionally releases the managed resources. /// </summary> /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param> protected virtual void Dispose(bool disposing) { if (m_disposed) return; try { if (!disposing) return; DataSet dataSource = DataSource; // Dispose filter adapters collection if (!(m_filterAdapters is null)) { m_filterAdapters.Stop(); m_filterAdapters.Dispose(); } m_filterAdapters = null; // Dispose input adapters collection if (!(m_inputAdapters is null)) { m_inputAdapters.Stop(); m_inputAdapters.NewMeasurements -= NewMeasurementsHandler; m_inputAdapters.ProcessingComplete -= ProcessingCompleteHandler; m_inputAdapters.Dispose(); } m_inputAdapters = null; // Dispose action adapters collection if (!(m_actionAdapters is null)) { m_actionAdapters.Stop(); m_actionAdapters.NewMeasurements -= NewMeasurementsHandler; m_actionAdapters.UnpublishedSamples -= UnpublishedSamplesHandler; m_actionAdapters.RequestTemporalSupport -= RequestTemporalSupportHandler; m_actionAdapters.Dispose(); } m_actionAdapters = null; // Dispose output adapters collection if (!(m_outputAdapters is null)) { m_outputAdapters.Stop(); m_outputAdapters.UnprocessedMeasurements -= UnprocessedMeasurementsHandler; m_outputAdapters.Dispose(); } m_outputAdapters = null; // Dispose all adapters collection if (!(m_allAdapters is null)) { m_allAdapters.StatusMessage -= StatusMessageHandler; m_allAdapters.ProcessException -= ProcessExceptionHandler; m_allAdapters.InputMeasurementKeysUpdated -= InputMeasurementKeysUpdatedHandler; m_allAdapters.OutputMeasurementsUpdated -= OutputMeasurementsUpdatedHandler; m_allAdapters.ConfigurationChanged -= ConfigurationChangedHandler; m_allAdapters.Disposed -= DisposedHandler; m_allAdapters.Dispose(); } m_allAdapters = null; // Dispose of routing tables if (!(m_routingTables is null)) { m_routingTables.StatusMessage -= m_routingTables_StatusMessage; m_routingTables.ProcessException -= m_routingTables_ProcessException; m_routingTables.Dispose(); } m_routingTables = null; dataSource?.Dispose(); } finally { m_disposed = true; // Prevent duplicate dispose. Disposed?.Invoke(this, EventArgs.Empty); } } /// <summary> /// Initialize and start adapters. /// </summary> /// <param name="autoStart">Sets flag that determines if adapters should be automatically started.</param> public virtual void Initialize(bool autoStart = true) { // Initialize all adapters m_allAdapters.Initialize(); // Start all adapters if they // haven't started already if (autoStart) m_allAdapters.Start(); } /// <summary> /// Gets flag that determines if temporal processing is supported in this <see cref="IaonSession"/>. /// </summary> /// <param name="collection">Name of collection over which to check support (e.g., "InputAdapters"); or <c>null</c> for all collections.</param> /// <returns>Flag that determines if temporal processing is supported in this <see cref="IaonSession"/>.</returns> public virtual bool TemporalProcessingSupportExists(string collection = null) { try { DataTable temporalSupport = m_allAdapters?.DataSource?.Tables["TemporalSupport"]; if (temporalSupport is null) return false; if (string.IsNullOrWhiteSpace(collection)) return temporalSupport.Rows.Count > 0; return temporalSupport.Select($"Source = '{collection}'").Length > 0; } catch (Exception ex) { Logger.SwallowException(ex, "Ignored Exception", "Failures are non-catastrophic and should only result in false."); return false; } } /// <summary> /// Gets derived name of specified object. /// </summary> /// <param name="sender">Sending object from which to derive name.</param> /// <returns>Derived name of specified object.</returns> public virtual string GetDerivedName(object sender) { string name = null; switch (sender) { case IProvideStatus statusProvider: name = statusProvider.Name; break; case string nameValue: name = nameValue; break; } if (string.IsNullOrWhiteSpace(name)) name = sender.GetType().Name; if (!string.IsNullOrWhiteSpace(m_name)) name += "#" + m_name; return name; }