using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.ServiceProcess;
using System.Threading;
using System.Timers;
using System.Xml;
using System.Configuration;
using MailTasks;
namespace SchedulerService
{
public partial class Scheduler : ServiceBase
{
private static ManualResetEvent doneEvent;
private static string configPath = string.Empty;
private static int numBusy;
private static DataSet dsTasks;
private const string TASKS_NAME_SPACE = "MailTasks.";
private const string DATE_FORMAT_STRING = "MM/dd/yyyy HH:mm";
private static Assembly tasksAssembly;
private static EventLog eventLog1;
readonly System.Timers.Timer _timer = new System.Timers.Timer();
private static bool workInProgress;
public Scheduler()
{
InitializeComponent();
if (!EventLog.SourceExists("MailScheduler"))
EventLog.CreateEventSource("MailScheduler", "Application" );
eventLog1 = new EventLog("Application", Environment.MachineName, "MailScheduler");
}
protected override void OnStart(string[] args)
{
try
{
eventLog1.WriteEntry("Mail Scheduler Service Started");
LoadTasksIntoDataSet();
LoadTasksAssembly();
_timer.Interval = 60000;
_timer.Elapsed += RunTasks;
_timer.Start();
}
catch (Exception ex)
{
eventLog1.WriteEntry("Error occurred OnStart "+ex.Message);
}
}
protected override void OnStop()
{
eventLog1.WriteEntry("MailScheduler service stopped");
try
{
UpdateTasksConfigonDisk();
}
catch(Exception ex)
{
eventLog1.WriteEntry("Error occurred onStop "+ex.Message);
}
}
private static void RunTasks(object sender, ElapsedEventArgs args)
{
if (workInProgress) return;
numBusy = 0;
doneEvent = new ManualResetEvent(false);
List<itask> tasksList = GetTasksToRun();
numBusy = tasksList.Count;
if (numBusy > 0)
{
workInProgress = true;
foreach (ITask task in tasksList)
{
ThreadPool.QueueUserWorkItem(DoTask, task);
}
doneEvent.WaitOne();
}
if (numBusy == 0 && tasksList.Count > 0)
{
workInProgress = false;
UpdateTasksConfigonDisk();
}
}
private static void DoTask(object o)
{
ITask task = o as ITask;
if (task == null) return;
string scheduleName = task.GetType().ToString();
try
{
task.RunTask();
int lastIndexOfPeriod = scheduleName.LastIndexOf(".");
UpdateNextRunTime(scheduleName.Substring(lastIndexOfPeriod + 1));
}
catch (Exception ex)
{
eventLog1.WriteEntry("Error occurred while executing task: " + scheduleName);
eventLog1.WriteEntry("Stack Trace is: " + ex.Message);
}
finally
{
if (Interlocked.Decrement(ref numBusy) == 0)
{
doneEvent.Set();
}
}
}
private static void LoadTasksIntoDataSet()
{
try
{
eventLog1.WriteEntry("Trying to Load Tasks into DataSet");
configPath = ConfigurationManager.AppSettings["tasksConfigPath"];
XmlTextReader xmlTextReader = new XmlTextReader(configPath);
XmlDataDocument xdoc1 = new XmlDataDocument();
xdoc1.DataSet.ReadXml(xmlTextReader, XmlReadMode.InferSchema);
dsTasks = xdoc1.DataSet;
xmlTextReader.Close();
eventLog1.WriteEntry("Finished Loading Tasks into DataSet");
}
catch(Exception ex)
{
eventLog1.WriteEntry("Error occurred while loading tasks into DataSet " + ex.Message);
throw;
}
}
private static void UpdateTasksConfigonDisk()
{
try
{
eventLog1.WriteEntry("Attempting to save tasks information to disk ");
StreamWriter sWrite = new StreamWriter(configPath);
XmlTextWriter xWrite = new XmlTextWriter(sWrite);
dsTasks.WriteXml(xWrite, XmlWriteMode.WriteSchema);
xWrite.Close();
}
catch (Exception ex)
{
eventLog1.WriteEntry("Error occurred while savings tasks information to disk "+ex.Message);
throw;
}
}
private static void UpdateNextRunTime(string taskName)
{
if (dsTasks == null) return;
foreach (DataRow row in dsTasks.Tables[0].Rows)
{
if (taskName.ToLower() != row[0].ToString().ToLower()) continue;
DateTime scheduledTime = DateTime.Parse(row[1].ToString());
string repeat = row["repeat"].ToString().ToUpper();
switch (repeat)
{
case "H":
scheduledTime = scheduledTime.AddHours(1);
if (scheduledTime < DateTime.Now)
scheduledTime = DateTime.Now.AddHours(1);
break;
case "D":
while (scheduledTime < DateTime.Now)
{
scheduledTime = scheduledTime.AddDays(1);
}
break;
case "W":
while (scheduledTime < DateTime.Now)
{
scheduledTime = scheduledTime.AddDays(7);
}
break;
case "M":
while (scheduledTime < DateTime.Now)
{
scheduledTime = scheduledTime.AddMonths(1);
}
break;
}
row[1] = scheduledTime.ToString(DATE_FORMAT_STRING);
dsTasks.AcceptChanges();
}
}
private static List<itask> GetTasksToRun()
{
if (dsTasks == null) return null;
List<itask> tasks = new List<itask>();
foreach (DataRow row in dsTasks.Tables[0].Rows)
{
DateTime scheduledTime = DateTime.Parse(row[1].ToString());
if (DateTime.Now < scheduledTime) continue;
ITask task = CreateTaskInstance(row[0].ToString());
if (task != null)
tasks.Add(task);
}
return tasks;
}
private static ITask CreateTaskInstance(string taskName)
{
string taskFullName = TASKS_NAME_SPACE + taskName;
try
{
if(tasksAssembly==null)
throw new Exception("Tasks Assembly is null, cannot proceed further..");
ITask task = (ITask)tasksAssembly.CreateInstance(taskFullName, true);
return task;
}
catch (Exception ex)
{
eventLog1.WriteEntry("Error occurred while creating Task Instance " + ex.Message);
}
return null;
}
private static void LoadTasksAssembly()
{
try
{
if (tasksAssembly == null)
tasksAssembly = Assembly.GetAssembly(typeof(MailTasks.ITask));
}
catch(Exception ex)
{
eventLog1.WriteEntry("Error occurred while loading tasks Assembly " + ex.Message);
throw;
}
}
}
}