//****************************************************************************************************** // 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 } }