//******************************************************************************************************
// ReplicationProviderBase.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:
// ----------------------------------------------------------------------------------------------------
// 11/04/2009 - Pinal C. Patel
// Generated original version of source code.
// 11/17/2009 - Pinal C. Patel
// Made Initialize(), SaveSettings() and LoadSettings() overridable in a derived class.
// 03/30/2010 - Pinal C. Patel
// Corrected the usage of Enabled in Replicate().
// 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 Timer = System.Timers.Timer;
namespace GSF.Historian.Replication
{
///
/// Base class for a provider of replication mechanism for the .
///
public abstract class ReplicationProviderBase : Adapter, IReplicationProvider
{
#region [ Members ]
// Events
///
/// Occurs when the process of replicating the is started.
///
public event EventHandler ReplicationStart;
///
/// Occurs when the process of replicating the is complete.
///
public event EventHandler ReplicationComplete;
///
/// Occurs when an is encountered during the replication process of .
///
public event EventHandler> ReplicationException;
///
/// Occurs when the is being replicated.
///
public event EventHandler>> ReplicationProgress;
// Fields
private string m_archiveLocation;
private string m_replicaLocation;
private int m_replicationInterval;
private Thread m_replicationThread;
private Timer m_replicationTimer;
private bool m_initialized;
private bool m_disposed;
#endregion
#region [ Constructors ]
///
/// Initializes a new instance of the replication provider.
///
protected ReplicationProviderBase()
{
m_replicationInterval = -1;
PersistSettings = true;
}
#endregion
#region [ Properties ]
///
/// Gets or sets the primary location of the .
///
public string ArchiveLocation
{
get
{
return m_archiveLocation;
}
set
{
m_archiveLocation = value;
}
}
///
/// Gets or sets the mirrored location of the .
///
public string ReplicaLocation
{
get
{
return m_replicaLocation;
}
set
{
m_replicaLocation = value;
}
}
///
/// Gets or sets the interval in minutes at which the is to be replicated.
///
public int ReplicationInterval
{
get
{
return m_replicationInterval;
}
set
{
if (value < 0)
m_replicationInterval = -1;
else
m_replicationInterval = value;
}
}
#endregion
#region [ Methods ]
///
/// When overridden in a derived class, replicates the .
///
protected abstract void ReplicateArchive();
///
/// Initializes the replication provider.
///
public override void Initialize()
{
base.Initialize();
if (!m_initialized)
{
// Start timer for periodic replication.
if (Enabled && m_replicationInterval > 0)
{
m_replicationTimer = new Timer(m_replicationInterval * 60000);
m_replicationTimer.Elapsed += ReplicationTimer_Elapsed;
m_replicationTimer.Start();
}
// Initialize only once.
m_initialized = true;
}
}
///
/// Saves replication 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["ArchiveLocation", true].Update(m_archiveLocation);
settings["ReplicaLocation", true].Update(m_replicaLocation);
settings["ReplicationInterval", true].Update(m_replicationInterval);
config.Save();
}
}
///
/// Loads saved replication 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 replication provider is enabled; otherwise False.");
settings.Add("ArchiveLocation", m_archiveLocation, "Path to the primary location of time-series data archive.");
settings.Add("ReplicaLocation", m_replicaLocation, "Path to the mirrored location of time-series data archive.");
settings.Add("ReplicationInterval", m_replicationInterval, "Interval in minutes at which the time-series data archive is to be replicated.");
Enabled = settings["Enabled"].ValueAs(Enabled);
ArchiveLocation = settings["ArchiveLocation"].ValueAs(m_archiveLocation);
ReplicaLocation = settings["ReplicaLocation"].ValueAs(m_replicaLocation);
ReplicationInterval = settings["ReplicationInterval"].ValueAs(m_replicationInterval);
}
}
///
/// Replicates the .
///
/// true if the replication is successful; otherwise false.
/// or is null or empty string.
public bool Replicate()
{
if (!Enabled || (m_replicationThread != null && m_replicationThread.IsAlive))
return false;
if (string.IsNullOrEmpty(m_archiveLocation))
throw new ArgumentNullException("ArchiveLocation");
if (string.IsNullOrEmpty(m_replicaLocation))
throw new ArgumentNullException("ReplicaLocation");
m_replicationThread = new Thread(ReplicateInternal);
m_replicationThread.Start();
m_replicationThread.Join();
return true;
}
///
/// Releases the unmanaged resources used by the replication 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
{
// This will be done regardless of whether the object is finalized or disposed.
if (disposing)
{
if (m_replicationThread != null)
m_replicationThread.Abort();
if (m_replicationTimer != null)
{
m_replicationTimer.Elapsed -= ReplicationTimer_Elapsed;
m_replicationTimer.Dispose();
}
}
}
finally
{
m_disposed = true; // Prevent duplicate dispose.
base.Dispose(disposing);
}
}
}
///
/// Raises the event.
///
protected virtual void OnReplicationStart()
{
if (ReplicationStart != null)
ReplicationStart(this, EventArgs.Empty);
}
///
/// Raises the event.
///
protected virtual void OnReplicationComplete()
{
if (ReplicationComplete != null)
ReplicationComplete(this, EventArgs.Empty);
}
///
/// Raises the event.
///
/// to send to event.
protected virtual void OnReplicationException(Exception ex)
{
if (ReplicationException != null)
ReplicationException(this, new EventArgs(ex));
}
///
/// Raises the event.
///
/// to send to event.
protected virtual void OnReplicationProgress(ProcessProgress replicationProgress)
{
if (ReplicationProgress != null)
ReplicationProgress(this, new EventArgs>(replicationProgress));
}
private void ReplicateInternal()
{
try
{
OnReplicationStart();
ReplicateArchive();
OnReplicationComplete();
}
catch (Exception ex)
{
OnReplicationException(ex);
}
}
private void ReplicationTimer_Elapsed(object sender, ElapsedEventArgs e)
{
Replicate();
}
#endregion
}
}