git_bsmd/ENI2/Util/DatabaseEntityWatchdog.cs

123 lines
5.2 KiB
C#

// Copyright (c) 2017 schick Informatik
// Description: Diese Klasse überwacht Änderungen in Datenbankobjekten (durch zykl. Abfrage eines Threads
// und Vgl. des "Changed" Felds bezogen auf den Beginn der Überwachung. Voraussetzung ist das die Entität ein
// entsprechendes "Changed" Feld besitzt. (aktuell nur MessageCore, generisch nicht so einfach weil DatabaseEntity
// aktuell eine abstrakte Klasse ist und daher nicht direkt instanziert werden kann (DBManager)
using System;
using System.Collections.Generic;
using System.Timers;
using bsmd.database;
namespace ENI2.Util
{
internal class DatabaseEntityWatchdog
{
private readonly Dictionary<MessageCore, DateTime> _watchedEntities = new Dictionary<MessageCore, DateTime>();
private readonly object _entityLock = new object();
private readonly Timer bgTimer;
public delegate void DatabaseEntityChangedHandler (DatabaseEntity entity);
public event DatabaseEntityChangedHandler DatabaseEntityChanged;
public event DatabaseEntityChangedHandler VisitTransitIdUpdated;
public DatabaseEntityWatchdog()
{
this.bgTimer = new Timer();
this.bgTimer.Elapsed += BgTimer_Elapsed;
this.bgTimer.AutoReset = true;
this.bgTimer.Interval = Properties.Settings.Default.changeTimerTimeout;
}
public bool Idle => _watchedEntities.Count == 0;
private void BgTimer_Elapsed(object sender, ElapsedEventArgs e)
{
lock (this._entityLock)
{
List<MessageCore> changedCores = new List<MessageCore>();
foreach (MessageCore watchedEntity in this._watchedEntities.Keys)
{
MessageCore entity = DBManager.GetSingleCon(Properties.Settings.Default.ConnectionString).GetMessageCoreById(watchedEntity.Id ?? Guid.Empty);
if (entity != null)
{
// Der Core muss einen dieser Zustände einnehmen bevor das Highlighting erlaubt ist. Diese Zustände werden im Send Prozess gesetzt
// (wenn die Nachrichten bearbeitet sind)
bool isValidState = (entity.BSMDStatusInternal == MessageCore.BSMDStatus.FAILURE) ||
(entity.BSMDStatusInternal == MessageCore.BSMDStatus.SENT) ||
(entity.BSMDStatusInternal == MessageCore.BSMDStatus.PREPARE) ||
(entity.BSMDStatusInternal == MessageCore.BSMDStatus.RESPONDED);
if (isValidState && ((entity.Changed > this._watchedEntities[watchedEntity]) || watchedEntity.IsHighlighted))
{
OnDatabaseEntityChanged(entity);
changedCores.Add(entity);
}
// Test ob eventuell Visit/Transit-ID inzwischen gesetzt wurde
if(entity.IsTransit)
{
if (!entity.TransitId.IsNullOrEmpty() && watchedEntity.TransitId.IsNullOrEmpty() && !entity.TransitId.Equals(watchedEntity.TransitId))
{
OnVisitTransitIdUpdated(entity);
watchedEntity.TransitId = entity.TransitId;
}
}
else if (!entity.VisitId.IsNullOrEmpty() && watchedEntity.VisitId.IsNullOrEmpty() && !entity.VisitId.Equals(watchedEntity.VisitId))
{
OnVisitTransitIdUpdated(entity);
watchedEntity.VisitId = entity.VisitId;
}
}
}
foreach (MessageCore changedCore in changedCores)
this._watchedEntities[changedCore] = DateTime.Now; // nur einmal auslösen
}
}
public void Register(MessageCore entity)
{
lock (this._entityLock)
{
if (!this._watchedEntities.ContainsKey(entity))
{
this._watchedEntities.Add(entity, DateTime.Now);
if (this._watchedEntities.Count > 0)
this.bgTimer.Start();
}
}
}
public void UnRegister(MessageCore entity)
{
lock (this._entityLock)
{
if (this._watchedEntities.ContainsKey(entity)) // hier wird mit Id verglichen (IEquatable<T> impl.)
this._watchedEntities.Remove(entity);
if (this._watchedEntities.Count == 0)
this.bgTimer.Stop();
}
}
#region private / protected
protected void OnDatabaseEntityChanged(DatabaseEntity entity)
{
this.DatabaseEntityChanged?.Invoke(entity);
}
protected void OnVisitTransitIdUpdated(DatabaseEntity entity)
{
this.VisitTransitIdUpdated?.Invoke(entity);
}
#endregion
}
}