//******************************************************************************************************// ActionAdapterBase.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:// ----------------------------------------------------------------------------------------------------// 09/02/2010 - J. Ritchie Carroll// Generated original version of source code.// 02/08/2011 - J. Ritchie Carroll// Added invokable ExamineQueueState method to analyze real-time concentrator frame queue state.// 12/20/2012 - Starlynn Danyelle Gilliam// Modified Header.////****************************************************************************************************** using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Diagnostics.CodeAnalysis;using System.Linq;using System.Text;using System.Threading;using GSF.Annotations;using GSF.Diagnostics; namespace GSF.TimeSeries.Adapters{ /// <summary> /// Represents the base class for action adapters. /// </summary> /// <remarks> /// This base class acts as a measurement concentrator which time aligns all incoming measurements for proper processing. /// Derived classes are expected to override <see cref="ConcentratorBase.PublishFrame"/> to handle time aligned measurements /// and call <see cref="OnNewMeasurements"/> for any new measurements that may get created. /// </remarks> [SuppressMessage("SonarQube.Methods", "S1206", Justification = "Class life-cycle is controlled through library.")] public abstract class ActionAdapterBase : ConcentratorBase, IActionAdapter { #region [ Members ] // Events /// <summary> /// Provides status messages to consumer. /// </summary> /// <remarks> /// <see cref="EventArgs{T}.Argument"/> is new status message. /// </remarks> public event EventHandler<EventArgs<string>> StatusMessage; /// <summary> /// Event is raised when <see cref="InputMeasurementKeys"/> are updated. /// </summary> public event EventHandler InputMeasurementKeysUpdated; /// <summary> /// Event is raised when <see cref="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> /// Provides new measurements from action adapter. /// </summary> /// <remarks> /// <see cref="EventArgs{T}.Argument"/> is a collection of new measurements for host to process. /// </remarks> public event EventHandler<EventArgs<ICollection<IMeasurement>>> NewMeasurements; // Fields private string m_name; private uint m_id; private string m_connectionString; private Dictionary<string, string> m_settings; private DataSet m_dataSource; private int m_initializationTimeout; private bool m_autoStart; private bool m_respectInputDemands; private bool m_respectOutputDemands; private MeasurementKey[] m_inputMeasurementKeys; private IMeasurement[] m_outputMeasurements; private MeasurementKey[] m_requestedInputMeasurementKeys; private MeasurementKey[] m_requestedOutputMeasurementKeys; private List<string> m_inputSourceIDs; private List<string> m_outputSourceIDs; private int m_minimumMeasurementsToUse; private DateTime m_startTimeConstraint; private DateTime m_stopTimeConstraint; private int m_hashCode; private bool m_initialized; private bool m_disposed; #endregion #region [ Constructors ] /// <summary> /// Creates a new <see cref="ActionAdapterBase"/>. /// </summary> protected ActionAdapterBase() { m_name = this.GetType().Name; Log.InitialStackMessages = Log.InitialStackMessages.Union("AdapterName", m_name); m_settings = new Dictionary<string, string>(); m_startTimeConstraint = DateTime.MinValue; m_stopTimeConstraint = DateTime.MaxValue; GenHashCode(); // Set incoming measurements to none by default m_inputMeasurementKeys = new MeasurementKey[0]; // For most implementations millisecond resolution will be sufficient base.TimeResolution = Ticks.PerMillisecond; } #endregion #region [ Properties ] /// <summary> /// Gets name of the action adapter. /// </summary> public virtual string Name { get { return m_name; } set { m_name = value; Log.InitialStackMessages = Log.InitialStackMessages.Union("AdapterName", m_name); GenHashCode(); } } /// <summary> /// Gets or sets numeric ID associated with this action adapter. /// </summary> public virtual uint ID { get { return m_id; } set { m_id = value; GenHashCode(); } } /// <summary> /// Gets or sets key/value pair connection information specific to action adapter. /// </summary> /// <remarks> /// <para> /// Example connection string using manually defined measurements:<br/> /// <c>framesPerSecond=30; lagTime=1.0; leadTime=0.5; minimumMeasurementsToUse=-1; /// useLocalClockAsRealTime=true; allowSortsByArrival=false;</c><br/> /// <c>inputMeasurementKeys={P1:1245;P1:1247;P2:1335};</c><br/> /// <c>outputMeasurements={P3:1345,60.0,1.0;P3:1346;P3:1347}</c><br/> /// When defined manually, elements in key:<br/> /// * inputMeasurementKeys are defined as "ArchiveSource:PointID"<br/> /// * outputMeasurements are defined as "ArchiveSource:PointID,Adder,Multiplier", the adder and multiplier are optional /// defaulting to 0.0 and 1.0 respectively. /// <br/> /// </para> /// <para> /// Example connection string using measurements defined in a <see cref="DataSource"/> table:<br/> /// <c>framesPerSecond=30; lagTime=1.0; leadTime=0.5; minimumMeasurementsToUse=-1; /// useLocalClockAsRealTime=true; allowSortsByArrival=false;</c><br/> /// <c>inputMeasurementKeys={FILTER ActiveMeasurements WHERE Company='GSF' AND SignalType='FREQ' ORDER BY ID};</c><br/> /// <c>outputMeasurements={FILTER ActiveMeasurements WHERE SignalType IN ('IPHA','VPHA') AND Phase='+'}</c><br/> /// <br/> /// Basic filtering syntax is as follows:<br/> /// <br/> /// {FILTER <TableName> WHERE <Expression> [ORDER BY <SortField>]}<br/> /// <br/> /// Source tables are expected to have at least the following fields:<br/> /// <list type="table"> /// <listheader> /// <term>Name</term> /// <term>Type</term> /// <description>Description.</description> /// </listheader> /// <item> /// <term>ID</term> /// <term>NVARCHAR</term> /// <description>Measurement key formatted as: ArchiveSource:PointID.</description> /// </item> /// <item> /// <term>PointTag</term> /// <term>NVARCHAR</term> /// <description>Point tag of measurement.</description> /// </item> /// <item> /// <term>Adder</term> /// <term>FLOAT</term> /// <description>Adder to apply to value, if any (default to 0.0).</description> /// </item> /// <item> /// <term>Multiplier</term> /// <term>FLOAT</term> /// <description>Multiplier to apply to value, if any (default to 1.0).</description> /// </item> /// </list> /// </para> /// <para> /// Note that framesPerSecond, lagTime and leadTime are required parameters, all other parameters are optional. /// </para> /// </remarks> public virtual string ConnectionString { get { return m_connectionString; } set { m_connectionString = value; // Pre-parse settings upon connection string assignment if (string.IsNullOrWhiteSpace(m_connectionString)) m_settings = new Dictionary<string, string>(); else m_settings = m_connectionString.ParseKeyValuePairs(); } } /// <summary> /// Gets connection info for adapter, if any. /// </summary> /// <remarks> /// For example, this could return IP or host name of source connection. /// </remarks> public virtual string ConnectionInfo => null; /// <summary> /// Gets or sets <see cref="DataSet"/> based data source available to this <see cref="ActionAdapterBase"/>. /// </summary> public virtual DataSet DataSource { get { return m_dataSource; } set { m_dataSource = value; } } /// <summary> /// Gets or sets maximum time system will wait during <see cref="Start"/> for initialization. /// </summary> /// <remarks> /// Set to <see cref="Timeout.Infinite"/> to wait indefinitely. /// </remarks> public virtual int InitializationTimeout { get { return m_initializationTimeout; } set { m_initializationTimeout = value; } } /// <summary> /// Gets or sets flag indicating if adapter should automatically start or otherwise connect on demand. /// </summary> public virtual bool AutoStart { get { return m_autoStart; } set { m_autoStart = value; } } /// <summary> /// Gets or sets flag indicating if action adapter should respect auto-start requests based on input demands. /// </summary> /// <remarks> /// Action adapters are in the curious position of being able to both consume and produce points, as such the user needs to be able to control how their /// adapter will behave concerning routing demands when the adapter is setup to connect on demand. In the case of respecting auto-start input demands, /// as an example, this would be <c>false</c> for an action adapter that calculated measurement, but <c>true</c> for an action adapter used to archive inputs. /// </remarks> public virtual bool RespectInputDemands { get { return m_respectInputDemands; } set { m_respectInputDemands = value; } } /// <summary> /// Gets or sets flag indicating if action adapter should respect auto-start requests based on output demands. /// </summary> /// <remarks> /// Action adapters are in the curious position of being able to both consume and produce points, as such the user needs to be able to control how their /// adapter will behave concerning routing demands when the adapter is setup to connect on demand. In the case of respecting auto-start output demands, /// as an example, this would be <c>true</c> for an action adapter that calculated measurement, but <c>false</c> for an action adapter used to archive inputs. /// </remarks> public virtual bool RespectOutputDemands { get { return m_respectOutputDemands; } set { m_respectOutputDemands = value; } } /// <summary> /// Gets or sets the number of frames per second. /// </summary> /// <remarks> /// Valid frame rates for a <see cref="ConcentratorBase"/> are greater than 0 frames per second. /// </remarks> [ConnectionStringParameter, Description("Defines the number of frames per second expected by the adapter.")] public new int FramesPerSecond { get { return base.FramesPerSecond; } set { base.FramesPerSecond = value; } } /// <summary> /// Gets or sets the allowed past time deviation tolerance, in seconds (can be sub-second). /// </summary> /// <remarks> /// <para>Defines the time sensitivity to past measurement timestamps.</para> /// <para>The number of seconds allowed before assuming a measurement timestamp is too old.</para> /// <para>This becomes the amount of delay introduced by the concentrator to allow time for data to flow into the system.</para> /// </remarks> /// <exception cref="ArgumentOutOfRangeException">LagTime must be greater than zero, but it can be less than one.</exception> [ConnectionStringParameter, Description("Defines the allowed past time deviation tolerance, in seconds (can be sub-second).")] public new double LagTime { get { return base.LagTime; } set { base.LagTime = value; } } /// <summary> /// Gets or sets the allowed future time deviation tolerance, in seconds (can be sub-second). /// </summary> /// <remarks> /// <para>Defines the time sensitivity to future measurement timestamps.</para> /// <para>The number of seconds allowed before assuming a measurement timestamp is too advanced.</para> /// <para>This becomes the tolerated +/- accuracy of the local clock to real-time.</para> /// </remarks> /// <exception cref="ArgumentOutOfRangeException">LeadTime must be greater than zero, but it can be less than one.</exception> [ConnectionStringParameter, Description("Defines the allowed future time deviation tolerance, in seconds (can be sub-second).")] public new double LeadTime { get { return base.LeadTime; } set { base.LeadTime = value; } } /// <summary> /// Gets or sets primary keys of input measurements the action adapter expects. /// </summary> /// <remarks> /// If your adapter needs to receive all measurements, you must explicitly set InputMeasurementKeys to null. /// </remarks> [ConnectionStringParameter, DefaultValue(null), Description("Defines primary keys of input measurements the action adapter expects; can be one of a filter expression, measurement key, point tag or Guid."), CustomConfigurationEditor("GSF.TimeSeries.UI.WPF.dll", "GSF.TimeSeries.UI.Editors.MeasurementEditor")] public virtual MeasurementKey[] InputMeasurementKeys { get { return m_inputMeasurementKeys; } set { if (m_inputMeasurementKeys == value) return; if ((object)m_inputMeasurementKeys != null && (object)value != null) { if (new HashSet<MeasurementKey>(m_inputMeasurementKeys).SetEquals(value)) return; } m_inputMeasurementKeys = value; // The input measurements typically define the "expected measurements" of the action adapter, so // we use the number of these items to define the expected measurement count ExpectedMeasurements = (object)m_inputMeasurementKeys != null ? m_inputMeasurementKeys.Length : 0; OnInputMeasurementKeysUpdated(); } } /// <summary> /// Gets or sets output measurements that the action adapter will produce, if any. /// </summary> [ConnectionStringParameter, DefaultValue(null), Description("Defines primary keys of output measurements the action adapter expects; can be one of a filter expression, measurement key, point tag or Guid."), CustomConfigurationEditor("GSF.TimeSeries.UI.WPF.dll", "GSF.TimeSeries.UI.Editors.MeasurementEditor")] public virtual IMeasurement[] OutputMeasurements { get { return m_outputMeasurements; } set { m_outputMeasurements = value; OnOutputMeasurementsUpdated(); } } /// <summary> /// Gets or sets <see cref="MeasurementKey.Source"/> values used to filter input measurement keys. /// </summary> /// <remarks> /// This allows an adapter to associate itself with entire collections of measurements based on the source of the measurement keys. /// Set to <c>null</c> apply no filter. /// </remarks> public virtual string[] InputSourceIDs { get { if ((object)m_inputSourceIDs == null) return null; return m_inputSourceIDs.ToArray(); } set { if ((object)value == null) { m_inputSourceIDs = null; } else { m_inputSourceIDs = new List<string>(value); m_inputSourceIDs.Sort(); } // Filter measurements to list of specified source IDs AdapterBase.LoadInputSourceIDs(this); } } /// <summary>Lines 1–500 of 1273. Load more
//****************************************************************************************************** // ActionAdapterBase.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: // ---------------------------------------------------------------------------------------------------- // 09/02/2010 - J. Ritchie Carroll // Generated original version of source code. // 02/08/2011 - J. Ritchie Carroll // Added invokable ExamineQueueState method to analyze real-time concentrator frame queue state. // 12/20/2012 - Starlynn Danyelle Gilliam // Modified Header. // //****************************************************************************************************** using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using System.Threading; using GSF.Annotations; using GSF.Diagnostics; namespace GSF.TimeSeries.Adapters { /// <summary> /// Represents the base class for action adapters. /// </summary> /// <remarks> /// This base class acts as a measurement concentrator which time aligns all incoming measurements for proper processing. /// Derived classes are expected to override <see cref="ConcentratorBase.PublishFrame"/> to handle time aligned measurements /// and call <see cref="OnNewMeasurements"/> for any new measurements that may get created. /// </remarks> [SuppressMessage("SonarQube.Methods", "S1206", Justification = "Class life-cycle is controlled through library.")] public abstract class ActionAdapterBase : ConcentratorBase, IActionAdapter { #region [ Members ] // Events /// <summary> /// Provides status messages to consumer. /// </summary> /// <remarks> /// <see cref="EventArgs{T}.Argument"/> is new status message. /// </remarks> public event EventHandler<EventArgs<string>> StatusMessage; /// <summary> /// Event is raised when <see cref="InputMeasurementKeys"/> are updated. /// </summary> public event EventHandler InputMeasurementKeysUpdated; /// <summary> /// Event is raised when <see cref="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> /// Provides new measurements from action adapter. /// </summary> /// <remarks> /// <see cref="EventArgs{T}.Argument"/> is a collection of new measurements for host to process. /// </remarks> public event EventHandler<EventArgs<ICollection<IMeasurement>>> NewMeasurements; // Fields private string m_name; private uint m_id; private string m_connectionString; private Dictionary<string, string> m_settings; private DataSet m_dataSource; private int m_initializationTimeout; private bool m_autoStart; private bool m_respectInputDemands; private bool m_respectOutputDemands; private MeasurementKey[] m_inputMeasurementKeys; private IMeasurement[] m_outputMeasurements; private MeasurementKey[] m_requestedInputMeasurementKeys; private MeasurementKey[] m_requestedOutputMeasurementKeys; private List<string> m_inputSourceIDs; private List<string> m_outputSourceIDs; private int m_minimumMeasurementsToUse; private DateTime m_startTimeConstraint; private DateTime m_stopTimeConstraint; private int m_hashCode; private bool m_initialized; private bool m_disposed; #endregion #region [ Constructors ] /// <summary> /// Creates a new <see cref="ActionAdapterBase"/>. /// </summary> protected ActionAdapterBase() { m_name = this.GetType().Name; Log.InitialStackMessages = Log.InitialStackMessages.Union("AdapterName", m_name); m_settings = new Dictionary<string, string>(); m_startTimeConstraint = DateTime.MinValue; m_stopTimeConstraint = DateTime.MaxValue; GenHashCode(); // Set incoming measurements to none by default m_inputMeasurementKeys = new MeasurementKey[0]; // For most implementations millisecond resolution will be sufficient base.TimeResolution = Ticks.PerMillisecond; } #endregion #region [ Properties ] /// <summary> /// Gets name of the action adapter. /// </summary> public virtual string Name { get { return m_name; } set { m_name = value; Log.InitialStackMessages = Log.InitialStackMessages.Union("AdapterName", m_name); GenHashCode(); } } /// <summary> /// Gets or sets numeric ID associated with this action adapter. /// </summary> public virtual uint ID { get { return m_id; } set { m_id = value; GenHashCode(); } } /// <summary> /// Gets or sets key/value pair connection information specific to action adapter. /// </summary> /// <remarks> /// <para> /// Example connection string using manually defined measurements:<br/> /// <c>framesPerSecond=30; lagTime=1.0; leadTime=0.5; minimumMeasurementsToUse=-1; /// useLocalClockAsRealTime=true; allowSortsByArrival=false;</c><br/> /// <c>inputMeasurementKeys={P1:1245;P1:1247;P2:1335};</c><br/> /// <c>outputMeasurements={P3:1345,60.0,1.0;P3:1346;P3:1347}</c><br/> /// When defined manually, elements in key:<br/> /// * inputMeasurementKeys are defined as "ArchiveSource:PointID"<br/> /// * outputMeasurements are defined as "ArchiveSource:PointID,Adder,Multiplier", the adder and multiplier are optional /// defaulting to 0.0 and 1.0 respectively. /// <br/> /// </para> /// <para> /// Example connection string using measurements defined in a <see cref="DataSource"/> table:<br/> /// <c>framesPerSecond=30; lagTime=1.0; leadTime=0.5; minimumMeasurementsToUse=-1; /// useLocalClockAsRealTime=true; allowSortsByArrival=false;</c><br/> /// <c>inputMeasurementKeys={FILTER ActiveMeasurements WHERE Company='GSF' AND SignalType='FREQ' ORDER BY ID};</c><br/> /// <c>outputMeasurements={FILTER ActiveMeasurements WHERE SignalType IN ('IPHA','VPHA') AND Phase='+'}</c><br/> /// <br/> /// Basic filtering syntax is as follows:<br/> /// <br/> /// {FILTER <TableName> WHERE <Expression> [ORDER BY <SortField>]}<br/> /// <br/> /// Source tables are expected to have at least the following fields:<br/> /// <list type="table"> /// <listheader> /// <term>Name</term> /// <term>Type</term> /// <description>Description.</description> /// </listheader> /// <item> /// <term>ID</term> /// <term>NVARCHAR</term> /// <description>Measurement key formatted as: ArchiveSource:PointID.</description> /// </item> /// <item> /// <term>PointTag</term> /// <term>NVARCHAR</term> /// <description>Point tag of measurement.</description> /// </item> /// <item> /// <term>Adder</term> /// <term>FLOAT</term> /// <description>Adder to apply to value, if any (default to 0.0).</description> /// </item> /// <item> /// <term>Multiplier</term> /// <term>FLOAT</term> /// <description>Multiplier to apply to value, if any (default to 1.0).</description> /// </item> /// </list> /// </para> /// <para> /// Note that framesPerSecond, lagTime and leadTime are required parameters, all other parameters are optional. /// </para> /// </remarks> public virtual string ConnectionString { get { return m_connectionString; } set { m_connectionString = value; // Pre-parse settings upon connection string assignment if (string.IsNullOrWhiteSpace(m_connectionString)) m_settings = new Dictionary<string, string>(); else m_settings = m_connectionString.ParseKeyValuePairs(); } } /// <summary> /// Gets connection info for adapter, if any. /// </summary> /// <remarks> /// For example, this could return IP or host name of source connection. /// </remarks> public virtual string ConnectionInfo => null; /// <summary> /// Gets or sets <see cref="DataSet"/> based data source available to this <see cref="ActionAdapterBase"/>. /// </summary> public virtual DataSet DataSource { get { return m_dataSource; } set { m_dataSource = value; } } /// <summary> /// Gets or sets maximum time system will wait during <see cref="Start"/> for initialization. /// </summary> /// <remarks> /// Set to <see cref="Timeout.Infinite"/> to wait indefinitely. /// </remarks> public virtual int InitializationTimeout { get { return m_initializationTimeout; } set { m_initializationTimeout = value; } } /// <summary> /// Gets or sets flag indicating if adapter should automatically start or otherwise connect on demand. /// </summary> public virtual bool AutoStart { get { return m_autoStart; } set { m_autoStart = value; } } /// <summary> /// Gets or sets flag indicating if action adapter should respect auto-start requests based on input demands. /// </summary> /// <remarks> /// Action adapters are in the curious position of being able to both consume and produce points, as such the user needs to be able to control how their /// adapter will behave concerning routing demands when the adapter is setup to connect on demand. In the case of respecting auto-start input demands, /// as an example, this would be <c>false</c> for an action adapter that calculated measurement, but <c>true</c> for an action adapter used to archive inputs. /// </remarks> public virtual bool RespectInputDemands { get { return m_respectInputDemands; } set { m_respectInputDemands = value; } } /// <summary> /// Gets or sets flag indicating if action adapter should respect auto-start requests based on output demands. /// </summary> /// <remarks> /// Action adapters are in the curious position of being able to both consume and produce points, as such the user needs to be able to control how their /// adapter will behave concerning routing demands when the adapter is setup to connect on demand. In the case of respecting auto-start output demands, /// as an example, this would be <c>true</c> for an action adapter that calculated measurement, but <c>false</c> for an action adapter used to archive inputs. /// </remarks> public virtual bool RespectOutputDemands { get { return m_respectOutputDemands; } set { m_respectOutputDemands = value; } } /// <summary> /// Gets or sets the number of frames per second. /// </summary> /// <remarks> /// Valid frame rates for a <see cref="ConcentratorBase"/> are greater than 0 frames per second. /// </remarks> [ConnectionStringParameter, Description("Defines the number of frames per second expected by the adapter.")] public new int FramesPerSecond { get { return base.FramesPerSecond; } set { base.FramesPerSecond = value; } } /// <summary> /// Gets or sets the allowed past time deviation tolerance, in seconds (can be sub-second). /// </summary> /// <remarks> /// <para>Defines the time sensitivity to past measurement timestamps.</para> /// <para>The number of seconds allowed before assuming a measurement timestamp is too old.</para> /// <para>This becomes the amount of delay introduced by the concentrator to allow time for data to flow into the system.</para> /// </remarks> /// <exception cref="ArgumentOutOfRangeException">LagTime must be greater than zero, but it can be less than one.</exception> [ConnectionStringParameter, Description("Defines the allowed past time deviation tolerance, in seconds (can be sub-second).")] public new double LagTime { get { return base.LagTime; } set { base.LagTime = value; } } /// <summary> /// Gets or sets the allowed future time deviation tolerance, in seconds (can be sub-second). /// </summary> /// <remarks> /// <para>Defines the time sensitivity to future measurement timestamps.</para> /// <para>The number of seconds allowed before assuming a measurement timestamp is too advanced.</para> /// <para>This becomes the tolerated +/- accuracy of the local clock to real-time.</para> /// </remarks> /// <exception cref="ArgumentOutOfRangeException">LeadTime must be greater than zero, but it can be less than one.</exception> [ConnectionStringParameter, Description("Defines the allowed future time deviation tolerance, in seconds (can be sub-second).")] public new double LeadTime { get { return base.LeadTime; } set { base.LeadTime = value; } } /// <summary> /// Gets or sets primary keys of input measurements the action adapter expects. /// </summary> /// <remarks> /// If your adapter needs to receive all measurements, you must explicitly set InputMeasurementKeys to null. /// </remarks> [ConnectionStringParameter, DefaultValue(null), Description("Defines primary keys of input measurements the action adapter expects; can be one of a filter expression, measurement key, point tag or Guid."), CustomConfigurationEditor("GSF.TimeSeries.UI.WPF.dll", "GSF.TimeSeries.UI.Editors.MeasurementEditor")] public virtual MeasurementKey[] InputMeasurementKeys { get { return m_inputMeasurementKeys; } set { if (m_inputMeasurementKeys == value) return; if ((object)m_inputMeasurementKeys != null && (object)value != null) { if (new HashSet<MeasurementKey>(m_inputMeasurementKeys).SetEquals(value)) return; } m_inputMeasurementKeys = value; // The input measurements typically define the "expected measurements" of the action adapter, so // we use the number of these items to define the expected measurement count ExpectedMeasurements = (object)m_inputMeasurementKeys != null ? m_inputMeasurementKeys.Length : 0; OnInputMeasurementKeysUpdated(); } } /// <summary> /// Gets or sets output measurements that the action adapter will produce, if any. /// </summary> [ConnectionStringParameter, DefaultValue(null), Description("Defines primary keys of output measurements the action adapter expects; can be one of a filter expression, measurement key, point tag or Guid."), CustomConfigurationEditor("GSF.TimeSeries.UI.WPF.dll", "GSF.TimeSeries.UI.Editors.MeasurementEditor")] public virtual IMeasurement[] OutputMeasurements { get { return m_outputMeasurements; } set { m_outputMeasurements = value; OnOutputMeasurementsUpdated(); } } /// <summary> /// Gets or sets <see cref="MeasurementKey.Source"/> values used to filter input measurement keys. /// </summary> /// <remarks> /// This allows an adapter to associate itself with entire collections of measurements based on the source of the measurement keys. /// Set to <c>null</c> apply no filter. /// </remarks> public virtual string[] InputSourceIDs { get { if ((object)m_inputSourceIDs == null) return null; return m_inputSourceIDs.ToArray(); } set { if ((object)value == null) { m_inputSourceIDs = null; } else { m_inputSourceIDs = new List<string>(value); m_inputSourceIDs.Sort(); } // Filter measurements to list of specified source IDs AdapterBase.LoadInputSourceIDs(this); } } /// <summary>