//******************************************************************************************************
// MetadataProviderBase.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/07/2009 - Pinal C. Patel
// Generated original version of source code.
// 08/06/2009 - Pinal C. Patel
// Made Initialize() virtual so inheriting classes can override the default behavior.
// 09/15/2009 - Stephen C. Wills
// Added new header and license agreement.
// 09/15/2009 - Pinal C. Patel
// Throwing ArgumentNullException exception in Refresh() if Metadata is null.
// 11/05/2009 - Pinal C. Patel
// Modified to abort refresh operation during dispose.
// 03/30/2010 - Pinal C. Patel
// Corrected the usage of Enabled in Refresh().
// 10/11/2010 - Mihir Brahmbhatt
// Updated header and license agreement.
// 12/14/2012 - Starlynn Danyelle Gilliam
// Modified Header.
//
//******************************************************************************************************
using System;
using System.Configuration;
using System.Threading;
using System.Timers;
using GSF.Adapters;
using GSF.Configuration;
using GSF.Historian.Files;
using Timer = System.Timers.Timer;
namespace GSF.Historian.MetadataProviders
{
///
/// Base class for a provider of updates to the data in a .
///
public abstract class MetadataProviderBase : Adapter, IMetadataProvider
{
#region [ Members ]
// Events
///
/// Occurs when of is started.
///
public event EventHandler MetadataRefreshStart;
///
/// Occurs when of is completed.
///
public event EventHandler MetadataRefreshComplete;
///
/// Occurs when of times out.
///
public event EventHandler MetadataRefreshTimeout;
///
/// Occurs when an is encountered during of .
///
///
/// is the encountered during .
///
public event EventHandler> MetadataRefreshException;
// Fields
private int m_refreshInterval;
private int m_refreshTimeout;
private MetadataFile m_metadata;
private Thread m_refreshThread;
private Timer m_refreshTimer;
private bool m_disposed;
private bool m_initialized;
#endregion
#region [ Constructors ]
///
/// Initializes a new instance of the metadata provider.
///
protected MetadataProviderBase()
{
m_refreshInterval = -1;
m_refreshTimeout = 60;
PersistSettings = true;
}
#endregion
#region [ Properties ]
///
/// Gets or sets the number of seconds to wait for the to complete.
///
///
/// Set to -1 to wait indefinitely on .
///
public int RefreshTimeout
{
get
{
return m_refreshTimeout;
}
set
{
if (value < 1)
m_refreshTimeout = -1;
else
m_refreshTimeout = value;
}
}
///
/// Gets or sets the interval in minutes at which the if to be refreshed automatically.
///
///
/// Set to -1 to disable auto .
///
public int RefreshInterval
{
get
{
return m_refreshInterval;
}
set
{
if (value < 1)
m_refreshInterval = -1;
else
m_refreshInterval = value;
}
}
///
/// Gets or sets the to be refreshed by the metadata provider.
///
public MetadataFile Metadata
{
get
{
return m_metadata;
}
set
{
m_metadata = value;
}
}
#endregion
#region [ Methods ]
///
/// When overridden in a derived class, refreshes the from an external source.
///
protected abstract void RefreshMetadata();
///
/// Initializes the metadata provider.
///
public override void Initialize()
{
base.Initialize();
if (!m_initialized)
{
// Start refresh timer for auto-refresh.
if (Enabled && m_refreshInterval > 0)
{
m_refreshTimer = new Timer(m_refreshInterval * 60000);
m_refreshTimer.Elapsed += RefreshTimer_Elapsed;
m_refreshTimer.Start();
}
// Initialize only once.
m_initialized = true;
}
}
///
/// Saves metadata provider settings to the config file if the property is set to true.
///
/// has a value of null or empty string.
public override void SaveSettings()
{
base.SaveSettings();
if (PersistSettings)
{
// Save settings under the specified category.
ConfigurationFile config = ConfigurationFile.Current;
CategorizedSettingsElementCollection settings = config.Settings[SettingsCategory];
settings["Enabled", true].Update(Enabled);
settings["RefreshTimeout", true].Update(m_refreshTimeout);
settings["RefreshInterval", true].Update(m_refreshInterval);
config.Save();
}
}
///
/// Loads saved metadata provider settings from the config file if the property is set to true.
///
/// has a value of null or empty string.
public override void LoadSettings()
{
base.LoadSettings();
if (PersistSettings)
{
// Load settings from the specified category.
ConfigurationFile config = ConfigurationFile.Current;
CategorizedSettingsElementCollection settings = config.Settings[SettingsCategory];
settings.Add("Enabled", Enabled, "True if this metadata provider is enabled; otherwise False.");
settings.Add("RefreshTimeout", m_refreshTimeout, "Number of seconds to wait for metadata refresh to complete.");
settings.Add("RefreshInterval", m_refreshInterval, "Interval in minutes at which the metadata is to be refreshed.");
Enabled = settings["Enabled"].ValueAs(Enabled);
RefreshTimeout = settings["RefreshTimeout"].ValueAs(m_refreshTimeout);
RefreshInterval = settings["RefreshInterval"].ValueAs(m_refreshInterval);
}
}
///
/// Refreshes the from an external source.
///
/// true if the is refreshed; otherwise false.
/// is null.
public bool Refresh()
{
if (!Enabled || (m_refreshThread != null && m_refreshThread.IsAlive))
return false;
if (m_metadata == null)
throw new ArgumentNullException("Metadata");
m_refreshThread = new Thread(RefreshInternal);
m_refreshThread.Start();
if (m_refreshTimeout < 1)
{
// Wait indefinetely on the refresh.
m_refreshThread.Join(Timeout.Infinite);
}
else
{
// Wait for the specified time on refresh.
if (!m_refreshThread.Join(m_refreshTimeout * 1000))
{
m_refreshThread.Abort();
return false;
}
}
return true;
}
///
/// Releases the unmanaged resources used by the metadata provider and optionally releases the managed resources.
///
/// true to release both managed and unmanaged resources; false to release only unmanaged resources.
protected override void Dispose(bool disposing)
{
if (!m_disposed)
{
try
{
if (disposing)
{
if (m_refreshThread != null)
m_refreshThread.Abort();
if (m_refreshTimer != null)
{
m_refreshTimer.Elapsed -= RefreshTimer_Elapsed;
m_refreshTimer.Dispose();
}
}
}
finally
{
m_disposed = true; // Prevent duplicate dispose.
base.Dispose(disposing);
}
}
}
///
/// Raises the event.
///
protected virtual void OnMetadataRefreshStart()
{
if (MetadataRefreshStart != null)
MetadataRefreshStart(this, EventArgs.Empty);
}
///
/// Raises the event.
///
protected virtual void OnMetadataRefreshComplete()
{
if (MetadataRefreshComplete != null)
MetadataRefreshComplete(this, EventArgs.Empty);
}
///
/// Raises the event.
///
protected virtual void OnMetadataRefreshTimeout()
{
if (MetadataRefreshTimeout != null)
MetadataRefreshTimeout(this, EventArgs.Empty);
}
///
/// Raises the event.
///
/// to send to event.
protected virtual void OnMetadataRefreshException(Exception ex)
{
if (MetadataRefreshException != null)
MetadataRefreshException(this, new EventArgs(ex));
}
private void RefreshInternal()
{
try
{
OnMetadataRefreshStart();
RefreshMetadata();
OnMetadataRefreshComplete();
}
catch (ThreadAbortException)
{
OnMetadataRefreshTimeout();
}
catch (Exception ex)
{
OnMetadataRefreshException(ex);
}
}
private void RefreshTimer_Elapsed(object sender, ElapsedEventArgs e)
{
Refresh();
}
#endregion
}
}