//******************************************************************************************************
// Subscribers.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 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:
// ----------------------------------------------------------------------------------------------------
// 05/20/2011 - Mehulbhai P Thakkar
// Generated original version of source code.
// 05/20/2011 - Mehulbhai P Thakkar
// Added commands and other logic to add or remove measurements and measurement groups.
//
//******************************************************************************************************
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using GSF.Collections;
using GSF.Data;
using GSF.TimeSeries.Transport.UI.DataModels;
using GSF.TimeSeries.UI;
using GSF.TimeSeries.UI.Commands;
using DataModelMeasurement = GSF.TimeSeries.UI.DataModels.Measurement;
namespace GSF.TimeSeries.Transport.UI.ViewModels
{
///
/// Class to hold bindable collection and current selection information for UI.
///
internal class Subscribers : PagedViewModelBase
{
#region [ Members ]
// Fields
private DataSet m_subscriberPermissionsDataSet;
private ICollection m_currentAvailableMeasurementsPage;
private object m_availableMeasurementsLock;
private RelayCommand m_addAllowedMeasurementGroupCommand;
private RelayCommand m_removeAllowedMeasurementGroupCommand;
private RelayCommand m_addDeniedMeasurementGroupCommand;
private RelayCommand m_removeDeniedMeasurementGroupCommand;
private DispatcherTimer m_refreshTimer;
private readonly SubscriberStatusQuery m_subscriberStatusQuery;
private readonly object m_subscriberStatusQueryLock;
private readonly List m_subscriberIDs;
private Func m_rightsLookup;
private SecurityMode m_securityMode;
private byte[] m_remoteCertificateData;
// Delegates
///
/// Method signature for a function which handles MeasurementsAdded event.
///
/// Source of an event.
/// Event arguments.
public delegate void OnMeasurementsAdded(object sender, RoutedEventArgs e);
// Event
///
/// Event to notify subscribers that measurements have been added to the group.
///
public event OnMeasurementsAdded MeasurementsAdded;
#endregion
#region [ Constructors ]
///
/// Creates an instance of class.
///
/// Integer value to determine number of items per page.
/// Boolean value to determine is user changes should be saved automatically.
public Subscribers(int itemsPerPage, bool autoSave = true)
: base(itemsPerPage, autoSave)
{
m_subscriberIDs = new List();
m_subscriberStatusQueryLock = new object();
m_subscriberStatusQuery = new SubscriberStatusQuery();
m_subscriberStatusQuery.SubscriberStatuses += m_subscriberStatusQuery_SubscriberStatuses;
PropertyChanged += PropertyChangedHandler;
}
#endregion
#region [ Properties ]
///
/// Gets flag that determines if is a new record.
///
public override bool IsNewRecord
{
get
{
return CurrentItem.ID == Guid.Empty;
}
}
///
/// Gets or sets measurements with Subscribed flag set to true.
///
public ICollection CurrentAvailableMeasurementsPage
{
get
{
lock (m_availableMeasurementsLock)
{
// Return a copy of the measurements since we can't request consumer to lock the collection
return new ObservableCollection(m_currentAvailableMeasurementsPage ?? new DataModelMeasurement[0]);
}
}
set
{
lock (m_availableMeasurementsLock)
{
m_currentAvailableMeasurementsPage = value;
}
UpdateEffectivePermissions();
}
}
///
/// Gets to add allowed measurement groups.
///
public ICommand AddAllowedMeasurementGroupCommand
{
get
{
if (m_addAllowedMeasurementGroupCommand == null)
m_addAllowedMeasurementGroupCommand = new RelayCommand(AddAllowedMeasurementGroup, (param) => CanSave);
return m_addAllowedMeasurementGroupCommand;
}
}
///
/// Gets to remove allowed measurement groups.
///
public ICommand RemoveAllowedMeasurementGroupCommand
{
get
{
if (m_removeAllowedMeasurementGroupCommand == null)
m_removeAllowedMeasurementGroupCommand = new RelayCommand(RemoveAllowedMeasurementGroup, (param) => CanSave);
return m_removeAllowedMeasurementGroupCommand;
}
}
///
/// Gets to add denied measurement groups.
///
public ICommand AddDeniedMeasurementGroupCommand
{
get
{
if (m_addDeniedMeasurementGroupCommand == null)
m_addDeniedMeasurementGroupCommand = new RelayCommand(AddDeniedMeasurementGroup, (param) => CanSave);
return m_addDeniedMeasurementGroupCommand;
}
}
///
/// Gets to remove denied measurement groups.
///
public ICommand RemoveDeniedMeasurementGroupCommand
{
get
{
if (m_removeDeniedMeasurementGroupCommand == null)
m_removeDeniedMeasurementGroupCommand = new RelayCommand(RemoveDeniedMeasurementGroup, (param) => CanSave);
return m_removeDeniedMeasurementGroupCommand;
}
}
///
/// Gets or sets the security mode used by the data Subscriber.
///
public SecurityMode SecurityMode
{
get
{
return m_securityMode;
}
set
{
m_securityMode = value;
OnPropertyChanged("SecurityMode");
OnPropertyChanged("TransportLayerSecuritySelected");
OnPropertyChanged("GatewaySecuritySelected");
}
}
///
/// Gets the flag that indicates whether the user has selected TLS as the security mode.
///
public bool TransportLayerSecuritySelected
{
get
{
return m_securityMode == SecurityMode.TLS;
}
}
///
/// Gets the flag that indicates whether the user has selected Gateway security.
///
public bool GatewaySecuritySelected
{
get
{
return m_securityMode == SecurityMode.Gateway;
}
}
///
/// Gets or sets the remote certificate file data that was imported from the subscription request file.
///
public byte[] RemoteCertificateData
{
get
{
return m_remoteCertificateData;
}
set
{
m_remoteCertificateData = value;
}
}
#endregion
#region [ Methods ]
private void m_subscriberStatusQuery_SubscriberStatuses(object sender, EventArgs>> e)
{
Dictionary> subscriberStatuses = e.Argument;
lock (m_subscriberStatusQueryLock)
{
foreach (Subscriber subscriber in ItemsSource)
{
Tuple status;
if (subscriberStatuses.TryGetValue(subscriber.ID, out status))
{
subscriber.StatusColor = status.Item1 ? "green" : "red";
subscriber.Version = status.Item2;
}
}
}
//OnPropertyChanged("ItemsSource");
}
///
/// Start refresh timer.
///
public void StartTimer()
{
try
{
if (m_refreshTimer == null)
{
m_refreshTimer = new DispatcherTimer();
m_refreshTimer.Interval = TimeSpan.FromSeconds(10);
m_refreshTimer.Tick += m_refreshTimer_Tick;
}
foreach (Subscriber subscriber in ItemsSource)
m_subscriberIDs.Add(subscriber.ID);
m_subscriberStatusQuery.RequestSubscriberStatus(m_subscriberIDs);
m_refreshTimer.Start();
}
catch (Exception ex)
{
Popup("Failed to start data refresh timer. Please reload page." + Environment.NewLine + ex.Message, "Refresh Data", MessageBoxImage.Error);
}
}
///
/// Stop refresh timer.
///
public void StopTimer()
{
try
{
if (m_refreshTimer != null)
m_refreshTimer.Stop();
}
finally
{
m_refreshTimer = null;
}
}
private void m_refreshTimer_Tick(object sender, EventArgs e)
{
lock (m_subscriberStatusQueryLock)
{
m_subscriberStatusQuery.RequestSubscriberStatus(m_subscriberIDs);
}
}
///
/// Gets the primary key value of the .
///
/// The primary key value of the .
public override Guid GetCurrentItemKey()
{
return CurrentItem.ID;
}
///
/// Gets the string based named identifier of the .
///
/// The string based named identifier of the .
public override string GetCurrentItemName()
{
return CurrentItem.Name;
}
///
/// Initialization to be done before the initial call to .
///
public override void Initialize()
{
m_availableMeasurementsLock = new object();
base.Initialize();
LoadPermissionsDataSet();
}
///
/// Saves the record for the associated .
///
public override void Save()
{
base.Save();
LoadPermissionsDataSet();
}
///
/// Handles .
///
/// Collection of measurements to be allowed.
public void AddAllowedMeasurements(ICollection measurementIDs)
{
int currentCount = Subscriber.GetMeasurementCount(null, CurrentItem.ID, true);
int addedCount = Subscriber.AddMeasurements(null, CurrentItem.ID, measurementIDs, true);
if (addedCount > 0)
{
DisplayStatusMessage("Measurements successfully added to allowed measurements list for subscriber");
// Log changes to event log
CommonFunctions.LogEvent(string.Format("Allowed {0} new measurements in addition to the {1} already allowed for subscriber {2} [{3}] for a total of {4} now allowed. See audit log for complete details.\r\n\r\nAction taken to add the following measurements: {5}", addedCount, currentCount, CurrentItem.Name.ToNonNullNorWhiteSpace("Subscriber"), CurrentItem.Acronym, currentCount + addedCount, ShortFormattedList(measurementIDs.Select(GetMeasurementName))), 0);
}
else
{
Popup("Selected measurements already exist or no measurements were selected.", "Allow Measurements", MessageBoxImage.Information);
}
MeasurementsAdded?.Invoke(this, null);
try
{
CommonFunctions.SendCommandToService("ReloadConfig");
}
catch (Exception ex)
{
CommonFunctions.LogException(null, "", ex);
}
LoadPermissionsDataSet();
}
///
/// Handles .
///
/// Collection of measurements to be disallowed.
public void RemoveAllowedMeasurements(ICollection measurementIDs)
{
int currentCount = Subscriber.GetMeasurementCount(null, CurrentItem.ID, true);
int removedCount = Subscriber.RemoveMeasurements(null, CurrentItem.ID, measurementIDs);
DisplayStatusMessage("Measurements successfully removed from allowed measurements list for subscriber");
// Log changes to event log
CommonFunctions.LogEvent(string.Format("Removed {0} measurements from the {1} currently allowed for subscriber {2} [{3}] for a total of {4} now allowed. See audit log for complete details.\r\n\r\nAction taken to remove the following measurements: {5}.", removedCount, currentCount, CurrentItem.Name.ToNonNullNorWhiteSpace("Subscriber"), CurrentItem.Acronym, currentCount - removedCount, ShortFormattedList(measurementIDs.Select(GetMeasurementName))), 0);
try
{
CommonFunctions.SendCommandToService("ReloadConfig");
}
catch (Exception ex)
{
CommonFunctions.LogException(null, "", ex);
}
LoadPermissionsDataSet();
}
///
/// Handles .
///
/// Collection of measurements to be denied.
public void AddDeniedMeasurements(ICollection measurementIDs)
{
int currentCount = Subscriber.GetMeasurementCount(null, CurrentItem.ID, false);
int addedCount = Subscriber.AddMeasurements(null, CurrentItem.ID, measurementIDs, false);
if (addedCount > 0)
{
DisplayStatusMessage("Measurements successfully added to denied measurements list for subscriber");
// Log changes to event log
CommonFunctions.LogEvent(string.Format("Denied {0} new measurements in addition to the {1} already denied for subscriber {2} [{3}] for a total of {4} now denied. See audit log for complete details.\r\n\r\nAction taken to add the following measurements: {5}", addedCount, currentCount, CurrentItem.Name.ToNonNullNorWhiteSpace("Subscriber"), CurrentItem.Acronym, currentCount + addedCount, ShortFormattedList(measurementIDs.Select(GetMeasurementName))), 0);
}
else
{
Popup("Selected measurements already exist or no measurements were selected.", "Deny Measurements", MessageBoxImage.Information);
}
MeasurementsAdded?.Invoke(this, null);
try
{
CommonFunctions.SendCommandToService("ReloadConfig");
}
catch (Exception ex)
{
CommonFunctions.LogException(null, "", ex);
}
LoadPermissionsDataSet();
}
///
/// Handles
///
/// Collection of measurements to be removed.
public void RemoveDeniedMeasurements(ICollection measurementIDs)
{
int currentCount = Subscriber.GetMeasurementCount(null, CurrentItem.ID, false);
int removedCount = Subscriber.RemoveMeasurements(null, CurrentItem.ID, measurementIDs);
DisplayStatusMessage("Measurements successfully removed from allowed measurements list for subscriber");
// Log changes to event log
CommonFunctions.LogEvent(string.Format("Removed {0} measurements from the {1} currently denied for subscriber {2} [{3}] for a total of {4} now denied. See audit log for complete details.\r\n\r\nAction taken to remove the following measurements: {5}.", removedCount, currentCount, CurrentItem.Name.ToNonNullNorWhiteSpace("Subscriber"), CurrentItem.Acronym, currentCount - removedCount, ShortFormattedList(measurementIDs.Select(GetMeasurementName))), 0);
try
{
CommonFunctions.SendCommandToService("ReloadConfig");
}
catch (Exception ex)
{
CommonFunctions.LogException(null, "", ex);
}
LoadPermissionsDataSet();
}
///
/// Determines if subscriber has rights to specified .
///
/// signal ID to lookup.
/// true if subscriber has rights to specified ; otherwise false.
public bool SubscriberHasRights(Guid signalID)
{
return m_rightsLookup(signalID);
}
///
/// Handles .
///
/// Collection of measurement groups to be added.
private void AddAllowedMeasurementGroup(object parameter)
{
ObservableCollection