You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

QuartzScheduler.cs 10 kB

15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web;
  5. using System.Collections.Specialized;
  6. using Quartz.Impl;
  7. using Quartz;
  8. using System.Data;
  9. using System.Configuration;
  10. using System.Collections;
  11. using System.Windows.Forms;
  12. using System.IO;
  13. using System.Xml.Linq;
  14. using Quartz.Impl.Matchers;
  15. using Quartz.Impl.Triggers;
  16. using Quartz.Util;
  17. namespace ClickForensics.Quartz.Manager
  18. {
  19. public class QuartzScheduler
  20. {
  21. public QuartzScheduler(string server, int port, string scheduler)
  22. {
  23. Address = string.Format("tcp://{0}:{1}/{2}", server, port, scheduler);
  24. _schedulerFactory = new StdSchedulerFactory(getProperties(Address));
  25. try
  26. {
  27. _scheduler = _schedulerFactory.GetScheduler();
  28. }
  29. catch (SchedulerException se)
  30. {
  31. MessageBox.Show("Unable to connect to the specified server", "Connection Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
  32. }
  33. }
  34. public string Address { get; private set; }
  35. private NameValueCollection getProperties(string address)
  36. {
  37. NameValueCollection properties = new NameValueCollection();
  38. properties["quartz.scheduler.instanceName"] = "RemoteClient";
  39. properties["quartz.scheduler.proxy"] = "true";
  40. properties["quartz.threadPool.threadCount"] = "0";
  41. properties["quartz.scheduler.proxy.address"] = address;
  42. return properties;
  43. }
  44. public IScheduler GetScheduler()
  45. {
  46. return _scheduler;
  47. }
  48. public DataTable GetJobs()
  49. {
  50. DataTable table = new DataTable();
  51. table.Columns.Add("GroupName");
  52. table.Columns.Add("JobName");
  53. table.Columns.Add("JobDescription");
  54. table.Columns.Add("TriggerName");
  55. table.Columns.Add("TriggerGroupName");
  56. table.Columns.Add("TriggerType");
  57. table.Columns.Add("TriggerState");
  58. table.Columns.Add("NextFireTime");
  59. table.Columns.Add("PreviousFireTime");
  60. var jobGroups = GetScheduler().GetJobGroupNames();
  61. foreach (string group in jobGroups)
  62. {
  63. var groupMatcher = GroupMatcher<JobKey>.GroupContains(group);
  64. var jobKeys = GetScheduler().GetJobKeys(groupMatcher);
  65. foreach (var jobKey in jobKeys)
  66. {
  67. var detail = GetScheduler().GetJobDetail(jobKey);
  68. var triggers = GetScheduler().GetTriggersOfJob(jobKey);
  69. foreach (ITrigger trigger in triggers)
  70. {
  71. DataRow row = table.NewRow();
  72. row["GroupName"] = group;
  73. row["JobName"] = jobKey.Name;
  74. row["JobDescription"] = detail.Description;
  75. row["TriggerName"] = trigger.Key.Name;
  76. row["TriggerGroupName"] = trigger.Key.Group;
  77. row["TriggerType"] = trigger.GetType().Name;
  78. row["TriggerState"] = GetScheduler().GetTriggerState(trigger.Key);
  79. DateTimeOffset? nextFireTime = trigger.GetNextFireTimeUtc();
  80. if (nextFireTime.HasValue)
  81. {
  82. row["NextFireTime"] = TimeZone.CurrentTimeZone.ToLocalTime(nextFireTime.Value.DateTime);
  83. }
  84. DateTimeOffset? previousFireTime = trigger.GetPreviousFireTimeUtc();
  85. if (previousFireTime.HasValue)
  86. {
  87. row["PreviousFireTime"] = TimeZone.CurrentTimeZone.ToLocalTime(previousFireTime.Value.DateTime);
  88. }
  89. table.Rows.Add(row);
  90. }
  91. }
  92. }
  93. return table;
  94. }
  95. public void ScheduleOneTimeJob(Type jobType, JobDataMap dataMap, int clientID)
  96. {
  97. string name = string.Format("{0}-{1}", jobType.Name, clientID);
  98. string group = clientID.ToString();
  99. IJobDetail jobDetail = JobBuilder.
  100. NewJob().
  101. OfType(jobType).
  102. WithIdentity(name, group).
  103. WithDescription("One time job").
  104. UsingJobData(dataMap).Build();
  105. ITrigger trigger = TriggerBuilder.
  106. Create().
  107. ForJob(jobDetail).
  108. WithIdentity(name, group).
  109. WithSchedule(SimpleScheduleBuilder.Create().WithRepeatCount(0).WithInterval(TimeSpan.Zero)).
  110. StartNow().Build();
  111. GetScheduler().ScheduleJob(jobDetail, trigger);
  112. }
  113. private ISchedulerFactory _schedulerFactory;
  114. private IScheduler _scheduler;
  115. public DataTable GetRunningJobs()
  116. {
  117. DataTable table = new DataTable();
  118. table.Columns.Add("JobName", typeof(string));
  119. table.Columns.Add("RunTime", typeof(int));
  120. try
  121. {
  122. var contexts = GetScheduler().GetCurrentlyExecutingJobs();
  123. foreach (var context in contexts)
  124. {
  125. DataRow row = table.NewRow();
  126. row["JobName"] = context.JobDetail.Key.Name;
  127. row["RunTime"] = (DateTime.Now.ToUniversalTime() - ((DateTimeOffset)context.FireTimeUtc).DateTime).TotalMinutes;
  128. table.Rows.Add(row);
  129. }
  130. }
  131. catch (Exception ex)
  132. {
  133. //TODO: Let the user know we couldn't load the running jobs.
  134. }
  135. return table;
  136. }
  137. public void BackupToFile(System.IO.FileInfo file)
  138. {
  139. IScheduler scheduler = GetScheduler();
  140. var jobGroupNames = scheduler.GetJobGroupNames();
  141. List<IJobDetail> jobDetails = new List<IJobDetail>();
  142. foreach (var jobGroup in jobGroupNames)
  143. {
  144. var groupMatcher = GroupMatcher<JobKey>.GroupContains(jobGroup);
  145. var jobKeys = scheduler.GetJobKeys(groupMatcher);
  146. foreach (var jobKey in jobKeys)
  147. {
  148. jobDetails.Add(scheduler.GetJobDetail(jobKey));
  149. }
  150. }
  151. writeToFile(file, jobDetails);
  152. }
  153. private void writeToFile(System.IO.FileInfo file, List<IJobDetail> jobDetails)
  154. {
  155. using (StreamWriter writer = file.CreateText())
  156. {
  157. XNamespace ns = "http://quartznet.sourceforge.net/JobSchedulingData";
  158. XDocument doc = new XDocument(new XDeclaration("1.0", "UTF-8", "yes")
  159. , new XElement(ns + "quartz"
  160. , new XAttribute(XNamespace.Xmlns + "xsi", "http://www.w3.org/2001/XMLSchema-instance")
  161. , new XAttribute("version", "1.0")
  162. , new XAttribute("overwrite-existing-jobs", "true")
  163. )
  164. );
  165. foreach (IJobDetail detail in jobDetails)
  166. {
  167. doc.Root.Add(
  168. new XElement(ns + "job"
  169. , new XElement(ns + "job-detail"
  170. , new XElement(ns + "name", detail.Key.Name)
  171. , new XElement(ns + "group", detail.Key.Group)
  172. , new XElement(ns + "description", detail.Description)
  173. , new XElement(ns + "job-type", detail.JobType.FullName + "," + detail.JobType.Assembly.FullName)
  174. //TODO: Apparently volatile is no longer available. Check.
  175. //, new XElement(ns + "volatile", detail.Volatile)
  176. , new XElement(ns + "durable", detail.Durable)
  177. , new XElement(ns + "recover", detail.RequestsRecovery)
  178. , getJobDataMap(ns, detail.JobDataMap)
  179. )
  180. , getTriggers(ns, detail)
  181. )
  182. );
  183. }
  184. writer.Write(doc);
  185. writer.Flush();
  186. writer.Close();
  187. }
  188. }
  189. private XElement getJobDataMap(XNamespace ns, JobDataMap jobDataMap)
  190. {
  191. XElement map = new XElement(ns + "job-data-map");
  192. foreach (var key in jobDataMap.GetKeys())
  193. {
  194. map.Add(new XElement(ns + "entry"
  195. , new XElement(ns + "key", key)
  196. , new XElement(ns + "value", jobDataMap[key])
  197. )
  198. );
  199. }
  200. return map;
  201. }
  202. private XElement[] getTriggers(XNamespace ns, IJobDetail detail)
  203. {
  204. var triggers = _scheduler.GetTriggersOfJob(detail.Key);
  205. XElement[] elements = new XElement[triggers.Count];
  206. int i = 0;
  207. foreach (var trigger in triggers)
  208. {
  209. elements[i] = new XElement(ns + "trigger");
  210. if (triggers[i] is SimpleTriggerImpl)
  211. {
  212. elements[i].Add(getSimpleTrigger(ns, (SimpleTriggerImpl)triggers[i]));
  213. }
  214. else if (triggers[i] is CronTriggerImpl)
  215. {
  216. elements[i].Add(getCronTrigger(ns, (CronTriggerImpl)triggers[i]));
  217. }
  218. i++;
  219. }
  220. return elements;
  221. }
  222. private XElement getCronTrigger(XNamespace ns, CronTriggerImpl trigger)
  223. {
  224. XElement cronTrigger = new XElement(ns + "cron");
  225. addCommonTriggerData(ns, cronTrigger, trigger);
  226. cronTrigger.Add(
  227. new XElement(ns + "cron-expression", trigger.CronExpressionString)
  228. );
  229. return cronTrigger;
  230. }
  231. private void addCommonTriggerData(XNamespace ns, XElement rootTriggerElement, AbstractTrigger trigger)
  232. {
  233. rootTriggerElement.Add(
  234. new XElement(ns + "name", trigger.Key.Name)
  235. , new XElement(ns + "group", trigger.Key.Group)
  236. , new XElement(ns + "description", trigger.Description)
  237. , new XElement(ns + "misfire-instruction", getMisfireInstructionText(trigger))
  238. //, new XElement(ns + "volatile", trigger.Volatile)
  239. , new XElement(ns + "job-name", trigger.JobName)
  240. , new XElement(ns + "job-group", trigger.JobGroup)
  241. );
  242. }
  243. private string getMisfireInstructionText(AbstractTrigger trigger)
  244. {
  245. if (trigger is CronTriggerImpl)
  246. {
  247. return getCronTriggerMisfireInstructionText(trigger.MisfireInstruction);
  248. }
  249. return getSimpleTriggerMisfireInstructionText(trigger.MisfireInstruction);
  250. }
  251. private string getSimpleTriggerMisfireInstructionText(int misfireInstruction)
  252. {
  253. switch (misfireInstruction)
  254. {
  255. case 0:
  256. return "SmartPolicy";
  257. case 1:
  258. return "FireNow";
  259. case 2:
  260. return "RescheduleNowWithExistingRepeatCount";
  261. case 3:
  262. return "RescheduleNowWithRemainingRepeatCount";
  263. case 4:
  264. return "RescheduleNextWithRemainingCount";
  265. case 5:
  266. return "RescheduleNextWithExistingCount";
  267. default:
  268. throw new ArgumentOutOfRangeException(string.Format("{0} is not a supported misfire instruction for SimpleTrigger See Quartz.MisfireInstruction for more details.", misfireInstruction));
  269. }
  270. }
  271. private string getCronTriggerMisfireInstructionText(int misfireInstruction)
  272. {
  273. switch (misfireInstruction)
  274. {
  275. case 0:
  276. return "SmartPolicy";
  277. case 1:
  278. return "FireOnceNow";
  279. case 2:
  280. return "DoNothing";
  281. default:
  282. throw new ArgumentOutOfRangeException(string.Format("{0} is not a supported misfire instruction for CronTrigger See Quartz.MisfireInstruction for more details.", misfireInstruction));
  283. }
  284. }
  285. private XElement getSimpleTrigger(XNamespace ns, SimpleTriggerImpl trigger)
  286. {
  287. XElement simpleTrigger = new XElement(ns + "simple");
  288. addCommonTriggerData(ns, simpleTrigger, trigger);
  289. simpleTrigger.Add(
  290. new XElement(ns + "repeat-count", trigger.RepeatCount)
  291. , new XElement(ns + "repeat-interval", trigger.RepeatInterval.Milliseconds)
  292. );
  293. return simpleTrigger;
  294. }
  295. }
  296. }