using System; using System.Collections.Generic; namespace Chernobyl.Threading { public class DataSafe { /// /// Constructor. /// public DataSafe() { AttachedDataAccessors = new List>(); ChangeRecords = new Queue.ChangeRecord>(); } /// /// Registers this DataSafe with a synchronous manager so that the DataSafe /// can be synchronized on the manager's workday schedule. /// /// The manager to register with. //public void Register(IManager manager) //{ // if (IsRegistered == true) // { // Code.WriteErrorMessage("Warning: this IDataSafe has already been registered."); // return; // } // // have the company call this DataSafe's synchronize // // when the workday has ended // manager.OnWorkdayEnd += this.SynchronizeEventHandler; // manager.OnDataSafeRegister(this); // IsRegistered = true; //} /// /// Attaches a DataAccessor so that accessor can read, write, etc, /// to the data within the accessor. /// /// The to attach. public void Attach(DataAccessor dataAccessor) { if (AccessRights.CanWrite == (dataAccessor.AccessRights & AccessRights.CanWrite)) { if (WriteAllowedDataAccessor == null) WriteAllowedDataAccessor = dataAccessor; else throw new Exception("Only one DataAccessor is allowed to have write access to the data in a DataSafe."); } if (AttachedDataAccessors.Contains(dataAccessor) == false) { AttachedDataAccessors.Add(dataAccessor); dataAccessor.OnAttach(this); } } /// /// Adds a to the internal list of /// changes. Only DataAccessors should call this method. The /// change record passed in must be able to mimic what was done /// to the data in the so that other /// DataAccessors will end with the same data. /// /// The ChangeRecord to add. public void RecordChange(DataAccessor recordingDataAccessor, ChangeRecord theChange) { if (ReferenceEquals(recordingDataAccessor, WriteAllowedDataAccessor) == true) ChangeRecords.Enqueue(theChange); else throw new Exception("Only DataAccessors which have write permissions can make changes to the DataSafe data."); } /// /// Can be used to added to an event to synchronize the /// data in this DataSafe. /// public void SynchronizeEventHandler(object sender, EventArgs e) { Synchronize(); } /// /// Synchronizes all of the attached DataAccessor's so that /// they all hold the newest value. /// public void Synchronize() { // no changes recorded, so we can just return. if (ChangeRecords.Count == 0) return; foreach (DataAccessor da in AttachedDataAccessors) { // don't update the write allowed data accessor // since he was the one to make a change if a // change exists. if(ReferenceEquals(da, WriteAllowedDataAccessor) == false) da.Synchronize(ChangeRecords); } ChangeRecords.Clear(); } /// /// Is true if this DataSafe has been registered with an /// ; false if otherwise. /// public bool IsRegistered { get; private set; } /// /// A delegate for specifying a ChangeRecord. ChangeRecords /// operate on the passed in so /// that the data held by the DataAccessors is all the same. /// /// public delegate void ChangeRecord(ref DataType oldValue); /// /// The ChangeRecords that will be applied on the next synchronize. /// Queue ChangeRecords {get; set;} /// /// The one that has write capabilities. Only one /// can have write capabilities. /// DataAccessor WriteAllowedDataAccessor {get; set;} /// /// The DataAccessors that are attached to this DataSafe so that /// they can read/write to it. /// List> AttachedDataAccessors {get; set;} } }