EnVisageOnline/Main-RMO/Source/EnVisage/App_Start/ContentLocker.cs

226 lines
7.9 KiB
C#

using EnVisage.Code;
using EnVisage.Properties;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Timers;
using System.Web;
namespace EnVisage.App_Start
{
public class LockerResponse
{
public enum ResponseCode
{
OK = 0,
ObjectLocked = 1,
ObjectExpired = 2,
}
public ResponseCode Code { get; set; }
public bool Status { get; set; }
public string LockedBy { get; set; }
public string EntityTitle { get; set; }
public LockerResponse()
{
Code = ResponseCode.OK;
}
}
public static class ContentLocker
{
static readonly Dictionary<string, string> EntityTitles = new Dictionary<string, string>
{
{"SystemSettings", "System Settings"},
{"Clients", "Client"},
{"CreditDepartment", "Credit Department"},
{"ExpenditureCategory", "Expenditure Category"},
{"GLAccount", "GL Account"},
{"Trainings", "Training"},
{"Vacations", "Vacation"},
{"ScenarioGroup", "Scenario Group"},
{"ExpenditureCategoryRate", "Rate"},
{"Project Statuses", "Project Status"},
{"Types", "Type"},
{"UnitOfMeasure", "Unit Of Measure"},
{"TrainingTypes", "Training Type"},
{"PeopleResource", "People Resource"}
};
static Timer timer;
static Dictionary<string, Dictionary<string, LockedElement>> lockersList;
static ContentLocker()
{
lockersList = new Dictionary<string, Dictionary<string, LockedElement>>();
timer = new Timer(Settings.Default.CheckInterval);
timer.Elapsed += checkDeadLocks;
if (!timer.Enabled)
timer.Start();
}
static void checkDeadLocks(object sender, ElapsedEventArgs e)
{
foreach (var lockedElement in lockersList)
{
unlockDead(lockedElement.Value);
}
}
static void unlockDead(Dictionary<string, LockedElement> lockedList)
{
List<string> unlockItems = new List<string>();
foreach (var lockedElement in lockedList)
{
if (lockedElement.Value.GetLockInterval() >= Settings.Default.UnlockInterval)
{
unlockItems.Add(lockedElement.Key);
}
}
foreach (var unlockId in unlockItems)
{
lockedList.Remove(unlockId);
}
}
/// <summary>
/// Adds an object lock to the dictionary (if possible) and returns result of this operation.
/// </summary>
/// <param name="tableId">Unique identifier of the database table in which we store the locked object.</param>
/// <param name="fieldId">Unique identifier of the locked object.</param>
/// <param name="owner">Username of the owner of the lock.</param>
/// <param name="timestamp">A timestamp of the object to check that system works with actual data.</param>
/// <returns>An instance of <see cref="LockerResponse"/> with info about operation result.</returns>
public static LockerResponse AddLock(String tableId, String fieldId, string owner, string timestamp)
{
// add a table to the main dictionary if there is no such table yet
if (!lockersList.ContainsKey(tableId))
{
lockersList.Add(tableId, new Dictionary<string, LockedElement>());
}
// if there is a lock on the specified object but made by another user then return failed result with info about locked object
if (lockersList[tableId].ContainsKey(fieldId) && lockersList[tableId][fieldId].Owner != owner)
{
return new LockerResponse { Status = false, Code=LockerResponse.ResponseCode.ObjectLocked, LockedBy = lockersList[tableId][fieldId].Owner, EntityTitle = GetLockedEntityTitle(tableId) };
}
// if there is a lock on the specified object made by current user then do not add lock and return successfull result
if (lockersList[tableId].ContainsKey(fieldId) && lockersList[tableId][fieldId].Owner == owner)
{
return new LockerResponse { Status = true, EntityTitle = GetLockedEntityTitle(tableId) };
}
// if there is no lock on the specified object but it has been updated since last access then return failed result with info about modified object
if (!IsObjectValid(tableId, fieldId, timestamp))
{
return new LockerResponse { Status = false, Code = LockerResponse.ResponseCode.ObjectExpired, EntityTitle = GetLockedEntityTitle(tableId) };
}
// add a lock to the specified object by current user
lockersList[tableId].Add(fieldId, new LockedElement(owner));
// return successfull result
return new LockerResponse { Status = true, EntityTitle = GetLockedEntityTitle(tableId) };
}
public static bool RemoveLock(String tableId, String fieldId, string owner)
{
if (!lockersList.ContainsKey(tableId))
{
return false;
}
if (!lockersList[tableId].ContainsKey(fieldId))
{
return false;
}
if (lockersList[tableId][fieldId].Owner == owner)
{
lockersList[tableId].Remove(fieldId);
return true;
}
return false;
}
public static bool UpdateLock(String tableId, String fieldId, string owner)
{
if (!lockersList.ContainsKey(tableId))
{
return false;
}
if (!lockersList[tableId].ContainsKey(fieldId))
{
return false;
}
if (lockersList[tableId][fieldId].Owner == owner)
{
lockersList[tableId][fieldId].UpdateLock();
return true;
}
return false;
}
public static string[] getLockList(String tableId)
{
if (lockersList.ContainsKey(tableId))
{
List<string> lockItems = new List<string>();
foreach (var lockedElement in lockersList)
{
lockItems.Add(lockedElement.Key);
}
return lockItems.ToArray();
}
return null;
}
public static LockerResponse IsLocked(String tableId, String fieldId, string owner)
{
if (lockersList.ContainsKey(tableId) && lockersList[tableId].ContainsKey(fieldId) && lockersList[tableId][fieldId].Owner != owner)
{
return new LockerResponse { Status = true, Code = LockerResponse.ResponseCode.ObjectLocked, LockedBy = lockersList[tableId][fieldId].Owner, EntityTitle = GetLockedEntityTitle(tableId) };
}
return new LockerResponse { Status = false, EntityTitle = GetLockedEntityTitle(tableId) };
}
public static bool IsLock(String tableId, String fieldId, string owner)
{
return IsLocked(tableId, fieldId, owner).Status;
}
public static string GetLockedEntityTitle(string tableId)
{
if (EntityTitles.ContainsKey(tableId))
return EntityTitles[tableId];
return tableId;
}
private static bool IsObjectValid(string tableId, string fieldId, string timestamp)
{
var projectValid = true;
if (string.IsNullOrWhiteSpace(timestamp))
return projectValid;
using (var dbContext = new EnVisageEntities())
{
switch(tableId)
{
case "Project":
var stamp = timestamp.StringToByteArray();
var id = Guid.Parse(fieldId);
projectValid = dbContext.Projects.Count(t => t.Id == id && t.DateEdited == stamp) > 0;
break;
default:
break;
}
}
return projectValid;
}
}
}