//******************************************************************************************************
// ActionAdapterCollection.cs - Gbtc
//
// Copyright © 2010, 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 Eclipse Public License -v 1.0 (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/eclipse-1.0.php
//
// 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.
//
//******************************************************************************************************
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace GSF.TimeSeries.Adapters
{
///
/// Represents a collection of implementations.
///
public class ActionAdapterCollection : AdapterCollectionBase, IActionAdapter
{
#region [ Members ]
// Events
///
/// This event will be raised when there are new measurements available from the action adapter.
///
///
/// is collection of new measurements for host to process.
///
public event EventHandler>> NewMeasurements;
///
/// This event is raised every five seconds allowing consumer to track current number of unpublished seconds of data in the queue.
///
///
/// is the total number of unpublished seconds of data.
///
public event EventHandler> UnpublishedSamples;
///
/// This event is raised if there are any measurements being discarded during the sorting process.
///
///
/// is the enumeration of values that are being discarded during the sorting process.
///
public event EventHandler>> DiscardingMeasurements;
// Fields
private bool m_respectInputDemands;
private bool m_respectOutputDemands;
#endregion
#region [ Constructors ]
///
/// Creates a new .
///
public ActionAdapterCollection()
: this(null)
{
// When collection is spawned as an adapter, it needs a parameterless constructor
}
///
/// Constructs a new instance of the .
///
/// Wait handle dictionary.
public ActionAdapterCollection(ConcurrentDictionary waitHandles)
: base(waitHandles)
{
base.Name = "Action Adapter Collection";
base.DataMember = "ActionAdapters";
}
#endregion
#region [ Properties ]
///
/// Gets or sets flag indicating if action adapter should respect auto-start requests based on input demands.
///
///
/// 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 false for an action adapter that calculated measurement, but true for an action adapter used to archive inputs.
///
public virtual bool RespectInputDemands
{
get
{
return m_respectInputDemands;
}
set
{
m_respectInputDemands = value;
}
}
///
/// Gets or sets flag indicating if action adapter should respect auto-start requests based on output demands.
///
///
/// 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 true for an action adapter that calculated measurement, but false for an action adapter used to archive inputs.
///
public virtual bool RespectOutputDemands
{
get
{
return m_respectOutputDemands;
}
set
{
m_respectOutputDemands = value;
}
}
///
/// Gets the descriptive status of this .
///
public override string Status
{
get
{
StringBuilder status = new StringBuilder();
status.Append(base.Status);
status.AppendFormat(" Respecting input demands: {0}", RespectInputDemands);
status.AppendLine();
status.AppendFormat(" Respecting output demands: {0}", RespectOutputDemands);
status.AppendLine();
return status.ToString();
}
}
#endregion
#region [ Methods ]
///
/// Initializes the .
///
public override void Initialize()
{
base.Initialize();
Dictionary settings = Settings;
string setting;
if (settings.TryGetValue("respectInputDemands", out setting))
RespectInputDemands = setting.ParseBoolean();
else
RespectInputDemands = false;
if (settings.TryGetValue("respectOutputDemands", out setting))
RespectOutputDemands = setting.ParseBoolean();
else
RespectOutputDemands = true;
}
///
/// Queues a collection of measurements for processing to each implementation in
/// this .
///
/// Measurements to queue for processing.
public virtual void QueueMeasurementsForProcessing(IEnumerable measurements)
{
try
{
lock (this)
{
foreach (IActionAdapter item in this)
{
if (item.Enabled)
item.QueueMeasurementsForProcessing(measurements);
}
}
}
catch (Exception ex)
{
OnProcessException(new InvalidOperationException("Failed to queue measurements to action adapters: " + ex.Message, ex));
}
}
///
/// Raises the event.
///
/// New measurements.
protected virtual void OnNewMeasurements(ICollection measurements)
{
try
{
if (NewMeasurements != null)
NewMeasurements(this, new EventArgs>(measurements));
}
catch (Exception ex)
{
// We protect our code from consumer thrown exceptions
OnProcessException(new InvalidOperationException(string.Format("Exception in consumer handler for NewMeasurements event: {0}", ex.Message), ex));
}
}
///
/// Raises the event.
///
/// Total number of unpublished seconds of data in the queue.
protected virtual void OnUnpublishedSamples(int unpublishedSamples)
{
try
{
if (UnpublishedSamples != null)
UnpublishedSamples(this, new EventArgs(unpublishedSamples));
}
catch (Exception ex)
{
// We protect our code from consumer thrown exceptions
OnProcessException(new InvalidOperationException(string.Format("Exception in consumer handler for UnpublishedSamples event: {0}", ex.Message), ex));
}
}
///
/// Raises the event.
///
/// Enumeration of values being discarded.
protected virtual void OnDiscardingMeasurements(IEnumerable measurements)
{
try
{
if (DiscardingMeasurements != null)
DiscardingMeasurements(this, new EventArgs>(measurements));
}
catch (Exception ex)
{
// We protect our code from consumer thrown exceptions
OnProcessException(new InvalidOperationException(string.Format("Exception in consumer handler for DiscardingMeasurements event: {0}", ex.Message), ex));
}
}
///
/// Wires events and initializes new implementation.
///
/// New implementation.
protected override void InitializeItem(IActionAdapter item)
{
if (item != null)
{
// Wire up events
item.NewMeasurements += item_NewMeasurements;
item.UnpublishedSamples += item_UnpublishedSamples;
item.DiscardingMeasurements += item_DiscardingMeasurements;
base.InitializeItem(item);
}
}
///
/// Unwires events and disposes of implementation.
///
/// to dispose.
protected override void DisposeItem(IActionAdapter item)
{
if (item != null)
{
// Un-wire events
item.NewMeasurements -= item_NewMeasurements;
item.UnpublishedSamples -= item_UnpublishedSamples;
item.DiscardingMeasurements -= item_DiscardingMeasurements;
base.DisposeItem(item);
}
}
// Raise new measurements event on behalf of each item in collection
private void item_NewMeasurements(object sender, EventArgs> e)
{
if (NewMeasurements != null)
NewMeasurements(sender, e);
}
// Raise unpublished samples event on behalf of each item in collection
private void item_UnpublishedSamples(object sender, EventArgs e)
{
if (UnpublishedSamples != null)
UnpublishedSamples(sender, e);
}
// Raise discarding measurements event on behalf of each item in collection
private void item_DiscardingMeasurements(object sender, EventArgs> e)
{
if (DiscardingMeasurements != null)
DiscardingMeasurements(sender, e);
}
#endregion
}
}