Files
Yaulw/Monitor/MonitorDataStore.cs
2016-02-15 12:32:26 -05:00

1699 lines
70 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Collections;
using System.IO;
using Yaulw.Process;
using Yaulw.Other;
using Yaulw.Xml;
namespace Yaulw.Monitor
{
#region XML Data Definition
/// <remarks>
/// Serializable Xml Object used to store Monitor Configuration data
/// </remarks>
[XmlRoot("configuration", Namespace = "Monitor", IsNullable = false)]
public class MonitorConfiguration : ICloneable
{
/// <summary>
/// MonitoredProcesses Member Tag <> holds list of ProcessExe's to Monitor
/// </summary>
public MonitoredProcessesW MonitoredProcesses = null;
/// <summary>
/// MonitoredServices Member Tag <> holds list of Services to Monitor
/// </summary>
public MonitoredServicesW MonitoredServices = null;
/// <summary>
/// Monitor Configuration - Constructor
/// </summary>
public MonitorConfiguration()
{
MonitoredProcesses = new MonitoredProcessesW();
MonitoredServices = new MonitoredServicesW();
}
#region Internal Monitor Properties N' Methods
/// <summary>
/// True if Either Any Processes or Any Services are Configured
/// </summary>
internal bool ConfiguredHasAny { get { return (MonitoredProcesses.ProcessExes.Length > 0 || MonitoredServices.ServiceExes.Length > 0); } }
/// <summary>
/// True if Any Processes are Configured
/// </summary>
internal bool ConfiguredHasAnyProcesses { get { return (MonitoredProcesses.ProcessExes.Length > 0); } }
/// <summary>
/// True if Any Services are Configured
/// </summary>
internal bool ConfiguredHasAnyServices { get { return (MonitoredServices.ServiceExes.Length > 0); } }
/// <summary>
/// Clears all Start and Fail Times for Both Processes and Services
/// </summary>
internal void ClearAllStartNFailTimes()
{
MonitoredProcesses.ClearProcessExeStartNFailTimes();
MonitoredServices.ClearServiceExeStartNFailTimes();
}
/// <summary>
/// Check to see if there are any Start or Fail Times,
/// if there aren't. Consider this configuration as newly loaded.
/// </summary>
/// <returns>true, if there are any Start or Fail Times recorded, false otherwise</returns>
internal bool HasAnyStartNFailTimes()
{
if (MonitoredProcesses.HasAnyProcessExeStartNFailTimes() ||
MonitoredServices.HasAnyServiceExeStartNFailTimes())
return true;
else
return false;
}
#endregion
/// <summary>
/// MonitoredProcessesW - (Wrapper) around ProcessExe ArrayList to work with XML
/// </summary>
public class MonitoredProcessesW : IComparable, ICloneable
{
#region Private Members
private ArrayList m_ArrayList;
#endregion
#region Construction
/// <summary>
/// Constructor for MonitoredProcessesW
/// </summary>
public MonitoredProcessesW()
{
m_ArrayList = new ArrayList();
}
#endregion
#region XML Process Element
/// <summary>
/// Property useful to directly Get/Set the ProcessExes as an Array
/// </summary>
[XmlElement("Process")]
public ProcessExe[] ProcessExes
{
get
{
ProcessExe[] processExes = new ProcessExe[m_ArrayList.Count];
m_ArrayList.CopyTo(processExes);
return processExes;
}
set
{
if (value == null) return;
ProcessExe[] processExes = (ProcessExe[])value;
m_ArrayList.Clear();
foreach (ProcessExe processExe in processExes)
AddProcessExe(processExe);
}
}
#endregion
#region Public Get Functions
/// <summary>
/// Use this to get all processes settings for a specific Process Exe File
/// </summary>
/// <param name="ProcessExeFileNameNPath">specific process exe to get settings for</param>
/// <returns>a list of process settings for the specified exe or empty list if not found</returns>
public ProcessExe[] GetProcessExesByProcessExeFileNameNPath(string ProcessExeFileNameNPath)
{
List<ProcessExe> foundProcessExes = new List<ProcessExe>();
foreach (ProcessExe _cmpProcessExe in m_ArrayList)
{
if (String.Compare(_cmpProcessExe.ProcessExeFileNameNPath, ProcessExeFileNameNPath, true) == 0)
foundProcessExes.Add(_cmpProcessExe);
}
return foundProcessExes.ToArray();
}
/// <summary>
/// Use this to get all processes settings for a specific Process Exe FileName without Extension
/// </summary>
/// <param name="ProcessExeFileNameWithoutExtension">specific process exe fileName without Extension to get settings for</param>
/// <returns>a list of process settings for the specified exe or empty list if not found</returns>
public ProcessExe[] GetProcessExesByProcessExeFileNameWithoutExtension(string ProcessExeFileNameWithoutExtension)
{
List<ProcessExe> foundProcessExes = new List<ProcessExe>();
foreach (ProcessExe _cmpProcessExe in m_ArrayList)
{
if (String.Compare(Path.GetFileNameWithoutExtension(_cmpProcessExe.ProcessExeFileNameNPath), ProcessExeFileNameWithoutExtension, true) == 0)
foundProcessExes.Add(_cmpProcessExe);
}
return foundProcessExes.ToArray();
}
#endregion
#region Public Add Functions
/// <summary>
/// Helper function to Add a Process Exe
/// </summary>
/// <param name="processExe">ProcessExe to Add</param>
/// <returns>true if successfull, false otherwise</returns>
public bool AddProcessExe(ProcessExe processExe)
{
bool bAddSuccess = false;
if (processExe != null && !String.IsNullOrEmpty(processExe.ProcessExeFileNameNPath))
{
if (processExe.CommandLinePrms == null)
processExe.CommandLinePrms = String.Empty;
if (processExe.WorkingDirectory == null)
processExe.WorkingDirectory = String.Empty;
ProcessExe pFound = null;
if (ProcessExeFileExistsLocally(processExe) && IsNotExcludedProcessExe(processExe) && IsUniqueProcessExe(processExe, out pFound))
{
bAddSuccess = (m_ArrayList.Add(processExe) >= 0);
}
else if (pFound != null)
{
// if Working Directory isn't the same, we allow updating it via AddProcessExe Call * Perform Update *
bAddSuccess = (String.Compare(pFound.WorkingDirectory, processExe.WorkingDirectory, true) != 0);
if (bAddSuccess)
pFound.WorkingDirectory = processExe.WorkingDirectory;
}
}
return bAddSuccess;
}
/// <summary>
/// Helper function to Add a Process Exe
/// </summary>
/// <param name="ProcessExeFileNameNPath">specify a fileName and path for a process</param>
/// <param name="CommandLinePrms">specify a command-line params to use for the process</param>
/// <param name="WorkingDirectory">specify the working directory to use for the process</param>
/// <returns>true if successfull, false otherwise</returns>
//public bool AddProcessExe(string ProcessExeFileNameNPath, string CommandLinePrms, string WorkingDirectory = "")
public bool AddProcessExe(string ProcessExeFileNameNPath, string CommandLinePrms, string WorkingDirectory)
{
bool bAddSuccess = false;
if (!String.IsNullOrEmpty(ProcessExeFileNameNPath))
{
if (CommandLinePrms == null)
CommandLinePrms = String.Empty;
if (WorkingDirectory == null)
WorkingDirectory = String.Empty;
ProcessExe processToAdd = new ProcessExe(Yaulw.Win32.Functions.GetLongFileNameNPathOrPath(ProcessExeFileNameNPath.Trim()), CommandLinePrms.Trim(), WorkingDirectory.Trim());
ProcessExe pFound = null;
if (ProcessExeFileExistsLocally(processToAdd) && IsNotExcludedProcessExe(processToAdd) && IsUniqueProcessExe(processToAdd, out pFound))
{
bAddSuccess = (m_ArrayList.Add(processToAdd) >= 0);
}
else if (pFound != null)
{
// if Working Directory isn't the same, we allow updating it via AddProcessExe Call * Perform Update *
bAddSuccess = (String.Compare(pFound.WorkingDirectory, processToAdd.WorkingDirectory, true) != 0);
if (bAddSuccess)
pFound.WorkingDirectory = processToAdd.WorkingDirectory;
}
}
return bAddSuccess;
}
/// <summary>
/// Helper function to check whether we can Add a Process Exe
/// </summary>
/// <param name="ProcessExeFileNameNPath">specify a fileName and path for a process</param>
/// <param name="CommandLinePrms">specify a command-line params to use for the process</param>
/// <param name="WorkingDirectory">specify the working directory to use for the process</param>
/// <returns>true if successfull, false otherwise</returns>
//public bool CanAddProcessExe(string ProcessExeFileNameNPath, string CommandLinePrms, string WorkingDirectory = "")
public bool CanAddProcessExe(string ProcessExeFileNameNPath, string CommandLinePrms, string WorkingDirectory)
{
bool bCanAddSuccess = false;
if (!String.IsNullOrEmpty(ProcessExeFileNameNPath))
{
if (CommandLinePrms == null)
CommandLinePrms = String.Empty;
if (WorkingDirectory == null)
WorkingDirectory = String.Empty;
ProcessExe processToAdd = new ProcessExe(Yaulw.Win32.Functions.GetLongFileNameNPathOrPath(ProcessExeFileNameNPath.Trim()), CommandLinePrms.Trim(), WorkingDirectory.Trim());
ProcessExe pFound = null;
if (ProcessExeFileExistsLocally(processToAdd) && IsNotExcludedProcessExe(processToAdd) && IsUniqueProcessExe(processToAdd, out pFound))
{
bCanAddSuccess = true;
}
else if(pFound != null)
{
// if Working Directory isn't the same, we allow updating it via AddProcessExe Call
bCanAddSuccess = (String.Compare(pFound.WorkingDirectory, processToAdd.WorkingDirectory, true) != 0);
}
}
return bCanAddSuccess;
}
#endregion
#region Public Remove Functions
/// <summary>
/// Helper function to Remove a Process Exe
/// </summary>
/// <param name="ProcessExeFileNameNPath">specify a fileName and path for a process</param>
/// <param name="CommandLinePrms">specify a command-line params to use for the process</param>
/// <param name="WorkingDirectory">specify the working directory to use for the process</param>
/// <returns>true if successfull, false otherwise</returns>
public bool RemoveProcessExe(string ProcessExeFileNameNPath, string CommandLinePrms)
{
if (!String.IsNullOrEmpty(ProcessExeFileNameNPath))
{
if (CommandLinePrms == null)
CommandLinePrms = String.Empty;
int nIndex = -1;
for (int i = 0; i < m_ArrayList.Count; ++i)
{
ProcessExe _cmpProcessExe = (ProcessExe)m_ArrayList[i];
if (_cmpProcessExe.FoundMatch(ProcessExeFileNameNPath.Trim(), CommandLinePrms.Trim()))
{
nIndex = i;
break;
}
}
if (nIndex != -1)
{
m_ArrayList.RemoveAt(nIndex);
return true;
}
}
return false;
}
#endregion
#region Public Clear N' Query Functions
/// <summary>
/// Clears all ProcessExes from the List
/// </summary>
public void Clear() { m_ArrayList.Clear(); }
/// <summary>
/// Clears each Process's Start and Fail Time
/// </summary>
public void ClearProcessExeStartNFailTimes() { foreach (ProcessExe p in ProcessExes) p.ClearStartNFailTimes(); }
/// <summary>
/// Check to see if there are any Start or Fail Times,
/// if there aren't. Consider this configuration as newly loaded.
/// </summary>
/// <returns>true, if there are any Start or Fail Times recorded, false otherwise</returns>
public bool HasAnyProcessExeStartNFailTimes() { foreach (ProcessExe p in ProcessExes) { if (p.LastFailedTimes.Count > 0) return true; } return false; }
/// <summary>
/// Retrieve the Process Exe that matches the specified PID
/// </summary>
public ProcessExe ClearPidInformation() { foreach (ProcessExe p in ProcessExes) { p.PID = 0; } return null; }
/// <summary>
/// Check to see if any of the Processes Configured has incomplete PID information, meaning that it never got started,
/// or failed to start, or was never mapped
/// </summary>
/// <returns>true, if any PID info is incomplete</returns>
public bool HasIncompletePidInformation() { foreach (ProcessExe p in ProcessExes) { if (p.PID <= 0) return true; } return false; }
/// <summary>
/// Retrieve a list of all Pids that have been mapped.
/// Make sure to call HasIncompletePidInformation() prior calling this if you want to make sure all pid are returned.
/// * Function only returns valid pids *
/// </summary>
/// <param name="bIncludeErrorStatePids">if set to true, includes Pids in an error state, false otherwise * should always use false *</param>
/// <returns>an array of pids mapped</returns>
//public uint[] QueryAllPidInfo(bool bIncludeErrorStatePids = false) { List<uint> pids = new List<uint>(); foreach (ProcessExe p in ProcessExes) { if (p.PID > 0) { if (bIncludeErrorStatePids && p.InErrorState) { pids.Add(p.PID); } else if (!bIncludeErrorStatePids && !p.InErrorState) { pids.Add(p.PID); } } } return pids.ToArray(); }
public uint[] QueryAllPidInfo(bool bIncludeErrorStatePids, bool bIncludeNonRestartPids)
{
List<uint> pids = new List<uint>();
foreach (ProcessExe p in ProcessExes)
{
if (p.PID > 0)
{
// bError = true && bInclude = true (include all)
// bError = false && bInclude = true (include all that don't have an error)
// bError = true && bInclude = false (include all that aren't restart)
// bError = false && bInclude = false (include none that have either)
if (bIncludeErrorStatePids && bIncludeNonRestartPids)
{
pids.Add(p.PID);
}
else if (!bIncludeErrorStatePids && bIncludeNonRestartPids)
{
if (!p.InErrorState)
pids.Add(p.PID);
}
else if (bIncludeErrorStatePids && !bIncludeNonRestartPids)
{
if (p.AllowRestart)
pids.Add(p.PID);
}
else if (!bIncludeErrorStatePids && !bIncludeNonRestartPids)
{
if (!p.InErrorState && p.AllowRestart)
pids.Add(p.PID);
}
}
}
return pids.ToArray();
}
/// <summary>
/// Retrieve the number of Processes now considered in an error state.
/// </summary>
/// <returns>Number of Pids in an error state</returns>
public uint NumberOfPidsInErrorState() { uint nErrorCount = 0; foreach (ProcessExe p in ProcessExes) { if (p.InErrorState) nErrorCount++; } return nErrorCount; }
/// <summary>
/// Retrieve the Process Exe that matches the specified PID
/// </summary>
/// <param name="PID">PID to look four</param>
/// <returns>ProcessExe that matches the PID, null otherwise (if not found)</returns>
public ProcessExe GetProcessExeForPid(uint PID) { foreach (ProcessExe p in ProcessExes) { if (p.PID == PID) return p; } return null; }
#endregion
#region Private Helper Functions
/// <summary>
/// Enforce Uniqueness, when adding Process Exe's to the DS
/// </summary>
/// <param name="processExe">a ProcessExe to check</param>
/// <param name="foundP">the found ProcessExe that matches the check</param>
/// <returns>true if unique, false otherwise</returns>
private bool IsUniqueProcessExe(ProcessExe processExe, out ProcessExe foundP)
{
foundP = null;
foreach (ProcessExe _cmpProcessExe in m_ArrayList)
{
// If ProcessExe FileName and Path, as well as CommandLine Prms Match, then it is NOT unique
if (_cmpProcessExe.FoundMatch(processExe.ProcessExeFileNameNPath, processExe.CommandLinePrms))
{
foundP = _cmpProcessExe;
return false;
}
}
return true;
}
/// <summary>
/// Enforce that the called didn't specify to exclude this Process
/// </summary>
/// <param name="processExe">a ProcessExe to check</param>
/// <returns>true if not exclusive, false otherwise</returns>
private bool IsNotExcludedProcessExe(ProcessExe processExe)
{
// * Allow caller via the Statically SPecified Exclusion list to filter out processes
// that are considered invalid *
if (MonitorDataStore.MonitoredProcessNamesExclusionList != null &&
MonitorDataStore.MonitoredProcessNamesExclusionList.Count > 0)
{
foreach (string ProcessName in MonitorDataStore.MonitoredProcessNamesExclusionList)
{
if (String.Compare(ProcessName, Path.GetFileNameWithoutExtension(processExe.ProcessExeFileNameNPath), true) == 0)
return false;
}
}
return true;
}
/// <summary>
/// Enforce that the Process/Exe File must exist on the system, prior being added
/// </summary>
/// <returns>true if exists, false otherwise</returns>
private bool ProcessExeFileExistsLocally(ProcessExe processExe)
{
return System.IO.File.Exists(processExe.ProcessExeFileNameNPath);
}
#endregion
#region IComparable Members
/// <summary>
/// Compares tow MonitoredProcessesW Objects with each other
/// </summary>
/// <param name="obj">Pass in a valid MonitoredProcessesW Object</param>
/// <returns>0 if equal, -1 if obj is smaller, 1 if obj is bigger</returns>
public int CompareTo(object obj)
{
if (obj is MonitoredProcessesW)
{
MonitoredProcessesW w = (MonitoredProcessesW)obj;
// First, do a simple count comparison
int wListCount = w.m_ArrayList.Count;
int thisListCount = this.m_ArrayList.Count;
if (wListCount == 0 && thisListCount != 0)
return -1;
else if (wListCount == 0 && thisListCount == 0)
return 0;
else if (wListCount != 0 && thisListCount == 0)
return 1;
else if (wListCount < thisListCount)
return -1;
else if (wListCount > thisListCount)
return 1;
// The count must be the same * Hence, now we must actually
// compare each member to make sure that the lists are the same *
// ~Before we do this we should sort both lists, so that we can correctly compare
ArrayList List1 = (ArrayList)w.m_ArrayList.Clone();
ArrayList List2 = (ArrayList)this.m_ArrayList.Clone();
List1.Sort();
List2.Sort();
// ~Iterate this Object's array list and compare each member
int nCompare = 0;
for (int i = 0; i < thisListCount; ++i)
{
ProcessExe p1 = (ProcessExe)List1[i];
ProcessExe p2 = (ProcessExe)List2[i];
nCompare = p1.CompareTo(p2);
if (nCompare != 0)
break;
}
// If they are both still exactly equal, then let's
// now also compare the order
if (nCompare == 0)
{
for (int i = 0; i < w.m_ArrayList.Count; ++i)
{
ProcessExe p1 = (ProcessExe) w.m_ArrayList[i];
ProcessExe p2 = (ProcessExe) this.m_ArrayList[i];
nCompare = p1.CompareTo(p2);
if (nCompare != 0)
break;
}
}
return nCompare;
}
else
{
throw new ArgumentException("object is not a MonitoredProcessesW");
}
}
#endregion
#region ICloneable Members
/// <summary>
/// Performs a Shallow Copy of MonitoredProcessesW
/// </summary>
/// <returns>a new MonitoredProcessesW Object</returns>
public object Clone()
{
MonitoredProcessesW w = new MonitoredProcessesW();
w.m_ArrayList = (ArrayList)this.m_ArrayList.Clone();
return w;
}
#endregion
}
/// <summary>
/// Process Exe (Image) Class that contains all settings to monitor
/// a process / executable image
/// </summary>
public class ProcessExe : IComparable, ICloneable
{
#region Public Properties
/// <summary>
/// specify a fileName and path for a process
/// </summary>
[XmlText]
public string ProcessExeFileNameNPath { get { return _ProcessExeFileNameNPath; } set { if (!String.IsNullOrEmpty(value)) _ProcessExeFileNameNPath = value; } }
private string _ProcessExeFileNameNPath = "";
/// <summary>
/// specify a command-line params to use for the process
/// </summary>
[XmlAttribute("CommandLinePrms")]
public string CommandLinePrms { get { if (String.IsNullOrEmpty(_CommandLinePrms)) return ""; else return _CommandLinePrms; } set { if (!String.IsNullOrEmpty(value)) _CommandLinePrms = value; } }
private string _CommandLinePrms = "";
/// <summary>
/// specify the working directory to use for the process
/// </summary>
[XmlAttribute("WorkingDirectory")]
public string WorkingDirectory { get { if(String.IsNullOrEmpty(_WorkingDirectory)) return ""; else return _WorkingDirectory; } set { if (!String.IsNullOrEmpty(value)) _WorkingDirectory = value; } }
private string _WorkingDirectory;
/// <summary>
/// specify if process is allowed to be restarted
/// </summary>
[XmlAttribute("AllowRestart")]
public bool AllowRestart { get { return _AllowRestart; } set { _AllowRestart = value; } }
private bool _AllowRestart = true;
#endregion
#region Construction
/// <summary>
/// Default Constructor * Don't use this * used only by serialization
/// </summary>
public ProcessExe()
{
this.PID = 0;
this.InErrorState = false;
}
/// <summary>
/// Main Constructor * Use this *
/// </summary>
/// <param name="ProcessExeFileNameNPath">specify a fileName and path for a process</param>
/// <param name="CommandLinePrms">specify a command-line params to use for the process</param>
/// <param name="WorkingDirectory">specify the working directory to use for the process</param>
public ProcessExe(string ProcessExeFileNameNPath, string CommandLinePrms, string WorkingDirectory)
{
if(!String.IsNullOrEmpty(ProcessExeFileNameNPath))
this.ProcessExeFileNameNPath = ProcessExeFileNameNPath.Trim();
if(!String.IsNullOrEmpty(CommandLinePrms))
this.CommandLinePrms = CommandLinePrms.Trim();
if(!String.IsNullOrEmpty(WorkingDirectory))
this.WorkingDirectory = WorkingDirectory.Trim();
this.PID = 0;
this.InErrorState = false;
}
#endregion
#region Internal Helper Functions N Properties
/// <summary>
/// The name of the Process
/// </summary>
internal string ProcessName
{
get
{
if (!String.IsNullOrEmpty(this.ProcessExeFileNameNPath))
{
string ProcessName = Path.GetFileNameWithoutExtension(this.ProcessExeFileNameNPath);
return ProcessName.ToLower();
}
return String.Empty;
}
}
/// <summary>
/// Clears all Start N' Fail Times for a process
/// </summary>
internal void ClearStartNFailTimes()
{
LastStartedTimes.Clear();
LastStartedTimes.Clear();
}
/// <summary>
/// Keep Track if this Process is in an Error State
/// </summary>
internal bool InErrorState;
/// <summary>
/// Internal Variable to Keep track of PID
/// </summary>
internal uint PID;
/// <summary>
/// Keep track of all Last Failed DT Stamps
/// </summary>
internal readonly List<DateTime> LastFailedTimes = new List<DateTime>();
/// <summary>
/// Keep track of all Last Started DT Stamps
/// </summary>
internal readonly List<DateTime> LastStartedTimes = new List<DateTime>();
/// <summary>
/// Returns the Last Failed Stamp
/// </summary>
internal DateTime LastFailTime
{
get
{
if (LastFailedTimes.Count > 0)
return LastFailedTimes.Last();
else
return DateTime.MinValue;
}
}
/// <summary>
/// Allow specific amount of time to have passed since Last-Fail
/// </summary>
/// <param name="ts">timespan that has to have occured since Last-Fail Time</param>
/// <returns>true if the Last-Fail Exceeded the specified amount of time, false otherwise</returns>
internal bool LastFailTimeTimeoutExceeded(TimeSpan ts)
{
if (LastFailedTimes.Count > 0)
{
TimeSpan diff = DateTime.Now - LastFailTime;
if (diff < ts)
return false;
}
return true;
}
/// <summary>
/// Returns the Last Started DT Stamp
/// </summary>
internal DateTime LastStartTime
{
get
{
if (LastStartedTimes.Count > 0)
return LastStartedTimes.Last();
else
return DateTime.MinValue;
}
}
/// <summary>
/// Allow specific amount of time to have passed since Last-Start
/// </summary>
/// <param name="ts">timespan that has to have occured since Last-Start Time</param>
/// <returns>true if the Last-Start Exceeded the specified amount of time, false otherwise</returns>
internal bool LastStartTimeTimeoutExceeded(TimeSpan ts)
{
if (LastStartedTimes.Count > 0)
{
TimeSpan diff = DateTime.Now - LastStartTime;
if (diff < ts)
return false;
}
return true;
}
/// <summary>
/// Add a FailTime to keep track of for the given process
/// </summary>
/// <param name="dtFail">Fail-Time</param>
/// <param name="nMaxCapacity">max capacity to store</param>
//internal void AddFailTime(DateTime dtFail, int nMaxCapacity = 1)
internal void AddFailTime(DateTime dtFail, int nMaxCapacity)
{
if (dtFail != DateTime.MinValue)
{
// Make sure to always at least store one
if (nMaxCapacity < 1)
nMaxCapacity = 1;
// Add and adjust according to capacity
LastFailedTimes.Add(dtFail);
if (LastFailedTimes.Count > nMaxCapacity)
{
int nRemoveCount = nMaxCapacity - LastFailedTimes.Count;
for (int i = 0; i < nRemoveCount; ++i)
LastFailedTimes.RemoveAt(i);
}
}
}
/// <summary>
/// Add a StartTime to keep track of for the given process
/// </summary>
/// <param name="dtStart">Start-Time</param>
/// <param name="nMaxCapacity">max capacity to store</param>
//internal void AddStartTime(DateTime dtStart, int nMaxCapacity = 1)
internal void AddStartTime(DateTime dtStart, int nMaxCapacity)
{
if (dtStart != DateTime.MinValue)
{
// Make sure to always at least store one
if (nMaxCapacity < 1)
nMaxCapacity = 1;
// Add and adjust according to capacity
LastStartedTimes.Add(dtStart);
if (LastStartedTimes.Count > nMaxCapacity)
{
int nRemoveCount = nMaxCapacity - LastStartedTimes.Count;
for (int i = 0; i < nRemoveCount; ++i)
LastStartedTimes.RemoveAt(i);
}
}
}
/// <summary>
/// Retrieves the Number of times the process failed in the given timespan
/// </summary>
/// <param name="span">TimeSpan to subtract from DateTime.Now</param>
/// <returns>number of times this Process Failed in the given timespan</returns>
internal int GetFailTimesInGivenTimeSpan(TimeSpan span)
{
if (LastFailedTimes.Count == 0)
return 0;
int nCount = 0;
DateTime dtMin = DateTime.Now - span;
foreach (DateTime dt in LastFailedTimes)
{
if (dt >= dtMin)
++nCount;
}
return nCount;
}
/// <summary>
/// Checks to see if the Number of times the process failed in the given timespan
/// exceeds nMaxTry
/// </summary>
/// <param name="nMaxTry">number of max times it is allowed to fail</param>
/// <param name="span">TimeSpan to subtract from DateTime.Now</param>
/// <returns>true if number of times in the given timespan exceeds nMaxTry, false otherwise</returns>
internal bool GetFailTimesInGivenTimeSpanMaxTryExceeded(TimeSpan span, uint nMaxTry)
{
if (LastFailedTimes.Count == 0)
return false;
int nCount = GetFailTimesInGivenTimeSpan(span);
return (nCount > nMaxTry);
}
/// <summary>
/// Retrieves the Number of times the process Started in the given timespan
/// </summary>
/// <param name="span">TimeSpan to subtract from DateTime.Now</param>
/// <returns>number of times this Process Started in the given timespan</returns>
internal int GetStartTimesInGivenTimeSpan(TimeSpan span)
{
if (LastStartedTimes.Count == 0)
return 0;
int nCount = 0;
DateTime dtMin = DateTime.Now - span;
foreach (DateTime dt in LastStartedTimes)
{
if (dt >= dtMin)
++nCount;
}
return nCount;
}
/// <summary>
/// Checks to see if the Number of times the process started in the given timespan
/// exceeds nMaxTry
/// </summary>
/// <param name="nMaxTry">number of max times it is allowed to have started</param>
/// <param name="span">TimeSpan to subtract from DateTime.Now</param>
/// <returns>true if number of times in the given timespan exceeds nMaxTry, false otherwise</returns>
internal bool GetStartTimesInGivenTimeSpanMaxTryExceeded(TimeSpan span, uint nMaxTry)
{
if (LastStartedTimes.Count == 0)
return false;
int nCount = GetStartTimesInGivenTimeSpan(span);
return (nCount > nMaxTry);
}
/// <summary>
/// Returns true if the passed in ProcessExeFileNameNPath, CommandLinePrms
/// matches this object's members * NOT THE SAME AS IComparable *
/// IComparable does a Full Compare, whereas this only Compares ProcessExeFileNameNPath and CommandLinePrms
/// ~IComparable also includes WorkingDirectory
/// </summary>
internal bool FoundMatch(string ProcessExeFileNameNPath, string CommandLinePrms)
{
if ((String.Compare(this.ProcessExeFileNameNPath.Trim(), ProcessExeFileNameNPath.Trim(), true) == 0) &&
(String.Compare(this.CommandLinePrms.Trim(), CommandLinePrms.Trim(), true) == 0))
{
return true;
}
return false;
}
#endregion
#region IComparable Members
/// <summary>
/// Compare the ProcessExe
/// </summary>
/// <param name="obj">a valid ProcessExe Obj</param>
/// <returns>0 if equal, -1 if obj is smaller, +1 if obj is bigger</returns>
public int CompareTo(object obj)
{
if (obj is ProcessExe)
{
ProcessExe p = (ProcessExe)obj;
int nCompare = String.Compare(p.ProcessExeFileNameNPath.Trim(), this.ProcessExeFileNameNPath.Trim(), true);
if (nCompare == 0)
nCompare = String.Compare(p.CommandLinePrms.Trim(), this.CommandLinePrms.Trim(), true);
if (nCompare == 0)
nCompare = String.Compare(p.WorkingDirectory.Trim(), this.WorkingDirectory.Trim(), true);
if (nCompare == 0)
nCompare = this.AllowRestart.CompareTo(p.AllowRestart);
return nCompare;
}
else
{
throw new ArgumentException("object is not a ProcessExe");
}
}
#endregion
#region ICloneable Members
/// <summary>
/// Clones the ProcessExe Object
/// </summary>
/// <returns>a new ProcessExe Object</returns>
public object Clone()
{
ProcessExe process = new ProcessExe(this.ProcessExeFileNameNPath, this.CommandLinePrms, this.WorkingDirectory);
process.AllowRestart = this.AllowRestart;
return process;
}
#endregion
}
/// <summary>
/// MonitoredServicesW - (Wrapper) around ServiceExe ArrayList to work with XML
/// </summary>
public class MonitoredServicesW : IComparable, ICloneable
{
#region Private Members
private ArrayList m_ArrayList;
#endregion
#region Construction
/// <summary>
/// Constructor for MonitoredServicesW
/// </summary>
public MonitoredServicesW()
{
m_ArrayList = new ArrayList();
}
#endregion
#region XML Service Element
/// <summary>
/// Property useful to directly Get/Set the ServiceExes as an Array
/// </summary>
[XmlElement("Service")]
public ServiceExe[] ServiceExes
{
get
{
ServiceExe[] serviceExes = new ServiceExe[m_ArrayList.Count];
m_ArrayList.CopyTo(serviceExes);
return serviceExes;
}
set
{
if (value == null) return;
ServiceExe[] serviceExes = (ServiceExe[])value;
m_ArrayList.Clear();
foreach (ServiceExe serviceExe in serviceExes)
AddServiceExe(serviceExe);
}
}
#endregion
#region Public Get Function
/// <summary>
/// Use this to get the ServiceExe Object for the Specified Service Name
/// </summary>
/// <param name="Name">Name of Service To look for</param>
/// <returns>the Service Exe Object or null, if not found</returns>
public ServiceExe GetServiceExeByServiceName(string Name)
{
if (String.IsNullOrEmpty(Name))
{
foreach (ServiceExe _cmpServiceExe in m_ArrayList)
{
if (String.Compare(_cmpServiceExe.Name, Name, true) == 0)
return _cmpServiceExe;
}
}
return null;
}
#endregion
#region Public Add Functions
/// <summary>
/// Helper function to Add a Service Exe
/// </summary>
/// <param name="serviceExe">a valid ServiceExe Object</param>
/// <returns>true if successfull, false otherwise</returns>
public bool AddServiceExe(ServiceExe serviceExe)
{
bool bAddSuccess = false;
if (serviceExe != null && !String.IsNullOrEmpty(serviceExe.Name))
{
if (ServiceExistsLocally(serviceExe) && IsUniqueServiceExe(serviceExe))
bAddSuccess = (m_ArrayList.Add(serviceExe) >= 0);
}
return bAddSuccess;
}
/// <summary>
/// Helper function to Add a Service Exe
/// </summary>
/// <param name="Name">Name of Service</param>
/// <returns>true if successfull, false otherwise</returns>
public bool AddServiceExe(string Name)
{
bool bAddSuccess = false;
if (!String.IsNullOrEmpty(Name))
{
ServiceExe serviceToAdd = new ServiceExe(Name.Trim());
if (ServiceExistsLocally(serviceToAdd) && IsUniqueServiceExe(serviceToAdd))
bAddSuccess = (m_ArrayList.Add(serviceToAdd) >= 0);
}
return bAddSuccess;
}
#endregion
#region Public Remove Function
/// <summary>
/// Helper function to Remove a Service Exe
/// </summary>
/// <param name="Name">Name of Service</param>
/// <returns>true if successfull, false otherwise</returns>
public bool RemoveServiceExe(string Name)
{
if (!String.IsNullOrEmpty(Name))
{
int nIndex = -1;
for (int i = 0; i < m_ArrayList.Count; ++i)
{
ServiceExe _cmpServiceExe = (ServiceExe)m_ArrayList[i];
if (_cmpServiceExe.FoundMatch(Name))
{
nIndex = i;
break;
}
}
if (nIndex != -1)
{
m_ArrayList.RemoveAt(nIndex);
return true;
}
}
return false;
}
#endregion
#region Public Clear N' Query Functions
/// <summary>
/// Clears all ServiceExes from the List
/// </summary>
public void Clear() { m_ArrayList.Clear(); }
/// <summary>
/// Clears each Services's Start and Fail Time
/// </summary>
public void ClearServiceExeStartNFailTimes() { foreach (ServiceExe s in ServiceExes) s.ClearStartNFailTimes(); }
/// <summary>
/// Check to see if there are any Start or Fail Times,
/// if there aren't. Consider this configuration as newly loaded.
/// </summary>
/// <returns>true, if there are any Start or Fail Times recorded, false otherwise</returns>
public bool HasAnyServiceExeStartNFailTimes() { foreach (ServiceExe s in ServiceExes) { if (s.LastFailedTimes.Count > 0) return true; } return false; }
/// <summary>
/// Retrieve a list of all Services that have been mapped
/// </summary>
/// <param name="bIncludeErrorStateServices">if set to true, includes Services in an error state, false otherwise * should always use false *</param>
/// <param name="bIncludeNonRestartServices">if set true, includes Services that are marked as NonRestart</param>
/// <returns></returns>
public string[] QueryAllServiceInfo(bool bIncludeErrorStateServices, bool bIncludeNonRestartServices)
{
List<string> services = new List<string>();
foreach (ServiceExe s in ServiceExes)
{
if (!String.IsNullOrEmpty(s.Name))
{
// bError = true && bInclude = true (include all)
// bError = false && bInclude = true (include all that don't have an error)
// bError = true && bInclude = false (include all that aren't restart)
// bError = false && bInclude = false (include none that have either)
if (bIncludeErrorStateServices && bIncludeNonRestartServices)
{
services.Add(s.Name);
}
else if (!bIncludeErrorStateServices && bIncludeNonRestartServices)
{
if (!s.InErrorState)
services.Add(s.Name);
}
else if (bIncludeErrorStateServices && !bIncludeNonRestartServices)
{
if (s.AllowRestart)
services.Add(s.Name);
}
else if (!bIncludeErrorStateServices && !bIncludeNonRestartServices)
{
if (!s.InErrorState && s.AllowRestart)
services.Add(s.Name);
}
}
}
return services.ToArray();
}
#endregion
#region Private Helper Functions
/// <summary>
/// Enforce Uniqueness, when adding Service Exe's to the DS
/// </summary>
/// <param name="serviceExe">a valid ServiceExe Object</param>
/// <returns>true if unique, false otherwise</returns>
private bool IsUniqueServiceExe(ServiceExe serviceExe)
{
foreach (ServiceExe _cmpServiceExe in m_ArrayList)
{
// If ServiceExe Name Matches, then it is NOT unique
if (_cmpServiceExe.FoundMatch(serviceExe.Name))
return false;
}
return true;
}
/// <summary>
/// Enforce that the Service must exist on the system, prior being added
/// </summary>
/// <param name="serviceExe">a valid ServiceExe Object</param>
/// <returns>true if exists, false otherwise</returns>
private bool ServiceExistsLocally(ServiceExe serviceExe)
{
bool bExists = ServiceW.DoesServiceExist(serviceExe.Name);
return bExists;
}
#endregion
#region IComparable Members
/// <summary>
/// Compares two MonitoredServicesW Objects
/// </summary>
/// <param name="obj">a valid MonitoredServicesW object</param>
/// <returns>0 if equal, -1 if obj is less, +1 if obj is more</returns>
public int CompareTo(object obj)
{
if (obj is MonitoredServicesW)
{
MonitoredServicesW sw = (MonitoredServicesW)obj;
// First, do a simple count comparison
int wListCount = sw.m_ArrayList.Count;
int thisListCount = this.m_ArrayList.Count;
if (wListCount == 0 && thisListCount != 0)
return -1;
else if (wListCount == 0 && thisListCount == 0)
return 0;
else if (wListCount != 0 && thisListCount == 0)
return 1;
else if (wListCount < thisListCount)
return -1;
else if (wListCount > thisListCount)
return 1;
// The count must be the same * Hence, now we must actually
// compare each member to make sure that the lists are the same *
// ~but before we do that, we must sort the List first
ArrayList List1 = (ArrayList) sw.m_ArrayList.Clone();
ArrayList List2 = (ArrayList) this.m_ArrayList.Clone();
List1.Sort();
List2.Sort();
// ~Iterate this Object's array list and compare each member
int nCompare = 0;
for (int i = 0; i < thisListCount; ++i)
{
ServiceExe s1 = (ServiceExe)List1[i];
ServiceExe s2 = (ServiceExe)List2[i];
nCompare = s1.CompareTo(s2);
if (nCompare != 0)
break;
}
// If they are both still exactly equal, then let's
// now also compare the order
if (nCompare == 0)
{
for (int i = 0; i < sw.m_ArrayList.Count; ++i)
{
ServiceExe s1 = (ServiceExe)sw.m_ArrayList[i];
ServiceExe s2 = (ServiceExe)this.m_ArrayList[i];
nCompare = s1.CompareTo(s2);
if (nCompare != 0)
break;
}
}
return nCompare;
}
else
{
throw new ArgumentException("object is not a MonitoredServicesW");
}
}
#endregion
#region ICloneable Members
/// <summary>
/// Creates a shallow copy of MonitoredServicesW Obj
/// </summary>
/// <returns>a new MonitoredServicesW Obj</returns>
public object Clone()
{
MonitoredServicesW sw = new MonitoredServicesW();
sw.m_ArrayList = (ArrayList)this.m_ArrayList.Clone();
return sw;
}
#endregion
}
/// <summary>
/// Service Name/Path Class that contains all settings to monitor a service
/// </summary>
public class ServiceExe : IComparable, ICloneable
{
#region Public Properties
/// <summary>
/// specify a Service Name
/// </summary>
[XmlText]
public string Name { get { return _Name; } set { if(!String.IsNullOrEmpty(value)) _Name = value; } }
private string _Name;
/// <summary>
/// specify if service is allowed to be restarted
/// </summary>
[XmlAttribute("AllowRestart")]
public bool AllowRestart { get { return _AllowRestart; } set { _AllowRestart = value; } }
private bool _AllowRestart = true;
#endregion
#region Construction
/// <summary>
/// Default Constructor * Don't use this * used only by serialization
/// </summary>
public ServiceExe()
{
this.InErrorState = false;
}
/// <summary>
/// Main Constructor * Use this *
/// </summary>
/// <param name="Name">specify the service Name</param>
public ServiceExe(string Name)
{
if (!String.IsNullOrEmpty(Name))
this.Name = Name.Trim();
this.InErrorState = false;
}
#endregion
#region Internal Helper Functions
/// <summary>
/// Returns true if the passed in Name matches this object's members *same as IComparable,
/// but func doesn't need creation of an object*
/// </summary>
/// <param name="Name">specify the service Name</param>
/// <returns>true if matched, false otherwise</returns>
internal bool FoundMatch(string Name)
{
if (Name != null)
{
if (String.Compare(this.Name.Trim(), Name.Trim(), true) == 0)
return true;
}
return false;
}
/// <summary>
/// Clears all Start N' Fail Times for a process
/// </summary>
internal void ClearStartNFailTimes()
{
LastStartedTimes.Clear();
LastStartedTimes.Clear();
}
/// <summary>
/// Internal Variable to keep track if this Process is in an Error State
/// </summary>
internal bool InErrorState;
/// <summary>
/// Keep track of all Last Failed DT Stamps
/// </summary>
internal readonly List<DateTime> LastFailedTimes = new List<DateTime>();
/// <summary>
/// Keep track of all Last Started DT Stamps
/// </summary>
internal readonly List<DateTime> LastStartedTimes = new List<DateTime>();
/// <summary>
/// Last Failed DT Stamp
/// </summary>
internal DateTime LastFailTime
{
get
{
if (LastFailedTimes.Count > 0)
return LastFailedTimes.Last();
else
return DateTime.MinValue;
}
}
/// <summary>
/// Allow specific amount of time to have passed since Last-Fail
/// </summary>
/// <param name="ts">timespan that has to have occured since Last-Fail Time</param>
/// <returns>true if the Last-Fail Exceeded the specified amount of time, false otherwise</returns>
internal bool LastFailTimeTimeoutExceeded(TimeSpan ts)
{
if (LastFailedTimes.Count > 0)
{
TimeSpan diff = DateTime.Now - LastFailTime;
if (diff < ts)
return false;
}
return true;
}
/// <summary>
/// Checks to see if the Number of times the process failed in the given timespan
/// exceeds nMaxTry
/// </summary>
/// <param name="nMaxTry">number of max times it is allowed to fail</param>
/// <param name="span">TimeSpan to subtract from DateTime.Now</param>
/// <returns>true if number of times in the given timespan exceeds nMaxTry, false otherwise</returns>
internal bool GetFailTimesInGivenTimeSpanMaxTryExceeded(TimeSpan span, uint nMaxTry)
{
if (LastFailedTimes.Count == 0)
return false;
int nCount = GetFailTimesInGivenTimeSpan(span);
return (nCount > nMaxTry);
}
/// <summary>
/// Last Started DT Stamp
/// </summary>
internal DateTime LastStartTime
{
get
{
if (LastStartedTimes.Count > 0)
return LastStartedTimes.Last();
else
return DateTime.MinValue;
}
}
/// <summary>
/// Allow specific amount of time to have passed since Last-Start
/// </summary>
/// <param name="ts">timespan that has to have occured since Last-Start Time</param>
/// <returns>true if the Last-Start Exceeded the specified amount of time, false otherwise</returns>
internal bool LastStartTimeTimeoutExceeded(TimeSpan ts)
{
if (LastStartedTimes.Count > 0)
{
TimeSpan diff = DateTime.Now - LastStartTime;
if (diff < ts)
return false;
}
return true;
}
/// <summary>
/// Checks to see if the Number of times the process started in the given timespan
/// exceeds nMaxTry
/// </summary>
/// <param name="nMaxTry">number of max times it is allowed to have started</param>
/// <param name="span">TimeSpan to subtract from DateTime.Now</param>
/// <returns>true if number of times in the given timespan exceeds nMaxTry, false otherwise</returns>
internal bool GetStartTimesInGivenTimeSpanMaxTryExceeded(TimeSpan span, uint nMaxTry)
{
if (LastStartedTimes.Count == 0)
return false;
int nCount = GetStartTimesInGivenTimeSpan(span);
return (nCount > nMaxTry);
}
/// <summary>
/// Add a FailTime to keep track of for the given Service
/// </summary>
/// <param name="dtFail">Fail-Time</param>
/// <param name="nMaxCapacity">max capacity to store</param>
//internal void AddFailTime(DateTime dtFail, int nMaxCapacity = 1)
internal void AddFailTime(DateTime dtFail, int nMaxCapacity)
{
if (dtFail != DateTime.MinValue)
{
// Make sure to always at least store one
if (nMaxCapacity < 1)
nMaxCapacity = 1;
// Add and adjust according to capacity
LastFailedTimes.Add(dtFail);
if (LastFailedTimes.Count > nMaxCapacity)
{
int nRemoveCount = nMaxCapacity - LastFailedTimes.Count;
for (int i = 0; i < nRemoveCount; ++i)
LastFailedTimes.RemoveAt(i);
}
}
}
/// <summary>
/// Add a StartTime to keep track of for the given Service
/// </summary>
/// <param name="dtStart">Start-Time</param>
/// <param name="nMaxCapacity">max capacity to store</param>
//internal void AddStartTime(DateTime dtStart, int nMaxCapacity = 1)
internal void AddStartTime(DateTime dtStart, int nMaxCapacity)
{
if (dtStart != DateTime.MinValue)
{
// Make sure to always at least store one
if (nMaxCapacity < 1)
nMaxCapacity = 1;
// Add and adjust according to capacity
LastStartedTimes.Add(dtStart);
if (LastStartedTimes.Count > nMaxCapacity)
{
int nRemoveCount = nMaxCapacity - LastStartedTimes.Count;
for (int i = 0; i < nRemoveCount; ++i)
LastStartedTimes.RemoveAt(i);
}
}
}
/// <summary>
/// Retrieves the Number of times the process failed / Started in the given timespan
/// </summary>
/// <param name="span">TimeSpan to subtract from DateTime.Now</param>
/// <returns>number of times this Process Failed in the given timespan</returns>
internal int GetFailTimesInGivenTimeSpan(TimeSpan span)
{
if (LastFailedTimes.Count == 0)
return 0;
int nCount = 0;
DateTime dtMin = DateTime.Now - span;
foreach (DateTime dt in LastFailedTimes)
{
if (dt >= dtMin)
++nCount;
}
return nCount;
}
/// <summary>
/// Retrieves the Number of times the process Started in the given timespan
/// </summary>
/// <param name="span">TimeSpan to subtract from DateTime.Now</param>
/// <returns>number of times this Process Started in the given timespan</returns>
internal int GetStartTimesInGivenTimeSpan(TimeSpan span)
{
if (LastStartedTimes.Count == 0)
return 0;
int nCount = 0;
DateTime dtMin = DateTime.Now - span;
foreach (DateTime dt in LastStartedTimes)
{
if (dt >= dtMin)
++nCount;
}
return nCount;
}
#endregion
#region IComparable Members
/// <summary>
/// Compare the ServiceExe
/// </summary>
/// <param name="obj">a valid ServiceExe Obj</param>
/// <returns>0 if equal, -1 if obj is smaller, +1 if obj is bigger</returns>
public int CompareTo(object obj)
{
if (obj is ServiceExe)
{
ServiceExe s = (ServiceExe)obj;
int nCompare = String.Compare(s.Name.Trim(), this.Name.Trim(), true);
if (nCompare == 0)
{
nCompare = this.AllowRestart.CompareTo(s.AllowRestart);
}
return nCompare;
}
else
{
throw new ArgumentException("object is not a ServiceExe");
}
}
#endregion
#region ICloneable Members
/// <summary>
/// Clones the ServiceExe Object
/// </summary>
/// <returns>a new ServiceExe Object</returns>
public object Clone()
{
ServiceExe service = new ServiceExe(this.Name);
service.AllowRestart = this.AllowRestart;
return service;
}
#endregion
}
#region ICloneable Members
public object Clone()
{
MonitorConfiguration config = new MonitorConfiguration();
config.MonitoredProcesses = (MonitoredProcessesW) this.MonitoredProcesses.Clone();
config.MonitoredServices = (MonitoredServicesW) this.MonitoredServices.Clone();
return config;
}
#endregion
}
#endregion
/// <remarks>
/// Object is responsible for Loading/Saving the MonitorConfiguration to
/// and From XML File.
/// </remarks>
public class MonitorDataStore
{
#region Private Members
private MonitorConfiguration _RunTimeWatchdogXMLConfigurationData = null;
private XSerializer _xmlserializer = null;
private string _dsFileNameNPath = "";
private DelegateCollection.Void_Param1_Exception_Func _exceptionHandler = null;
private bool _bForceRefreshOnNextRead = false;
private object _lock = new object();
#endregion
#region internal statics
internal static List<string> MonitoredProcessNamesExclusionList = null;
#endregion
#region Constructor
/// <summary>
/// Construct a MonitorDataStore Object, responsible for loading and
/// saving MonitorConfiguration from/to XML.
/// </summary>
/// <param name="dsFileNameNPath">a valid filename and path To load/store MonitorConfiguration</param>
/// <param name="ExclusionListProcessNames">List of Process Names that will always be consider excluded * invalid * to add to configuration</param>
/// <exception cref="ArgumentException">Thrown if Empty dsFileNameNPath is passed in</exception>
//public MonitorDataStore(string dsFileNameNPath, List<string> ExclusionListProcessNames = null, DelegateCollection.Void_Param1_Exception_Func exceptionHandler = null)
public MonitorDataStore(string dsFileNameNPath, List<string> ExclusionListProcessNames, DelegateCollection.Void_Param1_Exception_Func exceptionHandler)
{
if (String.IsNullOrEmpty(dsFileNameNPath))
throw new ArgumentException("Invalid dsFileNameNPath");
_dsFileNameNPath = dsFileNameNPath;
MonitoredProcessNamesExclusionList = ExclusionListProcessNames;
_exceptionHandler = exceptionHandler;
// Initialize Serializer And Try to Read File configuration
_xmlserializer = new XSerializer();
_RunTimeWatchdogXMLConfigurationData = _xmlserializer.ReadFromFile<MonitorConfiguration>(_dsFileNameNPath);
}
#endregion
#region Public Static Accessor Methods
/// <summary>
/// Use this function to force a Data Refresh the next time ReadData() is called
/// </summary>
public bool ForceRefreshOnNext_ReadData { get { return _bForceRefreshOnNextRead; } set { _bForceRefreshOnNextRead = value; } }
/// <summary>
/// Read the XML Configuration Data (From a File in the System) or from Cache
/// </summary>
/// <param name="bForceRefresh">set to true to force a reload of configuration from the disk</param>
/// <param name="exceptionHandler">Exception Handler Function, if an Exception is Thrown</param>
/// <returns>an XMLDataStore object or Null if error occured</returns>
//public WatchdogConfiguration ReadData(bool bForceRefresh = false)
public MonitorConfiguration ReadData(bool bForceRefresh)
{
try
{
// Force Refresh on next Call?
if (_bForceRefreshOnNextRead)
{
bForceRefresh = true;
_bForceRefreshOnNextRead = false;
}
// Load Configuration From the XML File
if (bForceRefresh || (_RunTimeWatchdogXMLConfigurationData == null))
{
// XML could have been modified by the user, hence we it is unverified
MonitorConfiguration UnverifiedConfig = _xmlserializer.ReadFromFile<MonitorConfiguration>(_dsFileNameNPath);
if(UnverifiedConfig != null)
{
// Make sure that all ProcessExes are Unique (ProcessExe and CommandLine and WorkingDirectory * together * are unique)
MonitorConfiguration VerifiedConfig = new MonitorConfiguration();
// calling AddProcessExe() will enforce uniqueness
foreach (MonitorConfiguration.ProcessExe p in UnverifiedConfig.MonitoredProcesses.ProcessExes)
VerifiedConfig.MonitoredProcesses.AddProcessExe(p);
// calling AddServiceExe() will enforce uniqueness
foreach (MonitorConfiguration.ServiceExe s in UnverifiedConfig.MonitoredServices.ServiceExes)
VerifiedConfig.MonitoredServices.AddServiceExe(s);
// always use the valid configuration
lock (_lock)
{
_RunTimeWatchdogXMLConfigurationData = VerifiedConfig;
}
// save the verified configuration xml * potentially fixing any issue that were in it *
SaveData();
}
}
}
catch (Exception e) { if (_exceptionHandler != null) _exceptionHandler(e); }
// No File Exists, write out a blank file * and load a default * blank * configuration
// This function should NEVER, EVER pass out null
if (_RunTimeWatchdogXMLConfigurationData == null)
{
SaveData(null);
_RunTimeWatchdogXMLConfigurationData = _xmlserializer.ReadFromFile<MonitorConfiguration>(_dsFileNameNPath);
}
return _RunTimeWatchdogXMLConfigurationData;
}
/// <summary>
/// Writes the XML Configuration Data passed in out to Disk
/// </summary>
/// <param name="data">The XML Data To Write out</param>
/// <param name="exceptionHandler">Exception Handler Function, if an Exception is Thrown</param>
public void SaveData(MonitorConfiguration data)
{
try
{
_xmlserializer.WriteToFile<MonitorConfiguration>(data, _dsFileNameNPath);
lock (_lock)
{
_RunTimeWatchdogXMLConfigurationData = data;
}
}
catch (Exception e) { if (_exceptionHandler != null) _exceptionHandler(e); }
}
/// <summary>
/// Writes the XML Configuration Data that is currently stored in this Object out to Disk
/// </summary>
/// <param name="exceptionHandler">Exception Handler Function, if an Exception is Thrown</param>
public void SaveData()
{
try
{
_xmlserializer.WriteToFile<MonitorConfiguration>(_RunTimeWatchdogXMLConfigurationData, _dsFileNameNPath);
}
catch (Exception e) { if (_exceptionHandler != null) _exceptionHandler(e); }
}
#endregion
}
}