@@ -1,4 +1,6 @@ | |||
obj/ | |||
bin/ | |||
*.user | |||
*.suo | |||
*.suo | |||
*.exe | |||
*.msi |
@@ -8,169 +8,171 @@ using System.Text; | |||
using System.Windows.Forms; | |||
using Quartz; | |||
using System.Reflection; | |||
using Quartz.Impl; | |||
using Quartz.Impl.Triggers; | |||
using Quartz.Job; | |||
using System.IO; | |||
namespace ClickForensics.Quartz.Manager | |||
{ | |||
public partial class AddJobForm : Form | |||
{ | |||
public AddJobForm() | |||
{ | |||
InitializeComponent(); | |||
loadJobAssemblies(); | |||
cboTriggerType.Items.Add("Cron"); | |||
cboTriggerType.SelectedItem = "Cron"; | |||
if (cboJobType.SelectedText == "NativeJob") | |||
{ | |||
jobDataListView.Items.Add(new ListViewItem(new string[] { "consumeStreams", "true" })); | |||
jobDataListView.Items.Add(new ListViewItem(new string[] { "waitForProcess", "true" })); | |||
txtKey.Text = "command"; | |||
} | |||
} | |||
private void loadJobAssemblies() | |||
{ | |||
FileStream stream = File.OpenRead("JobAssemblies.txt"); | |||
StreamReader reader = new StreamReader(stream); | |||
string line; | |||
SortedList<string, string> jobTypes = new SortedList<string, string>(); | |||
while ((line = reader.ReadLine()) != null) | |||
{ | |||
Assembly assembly = Assembly.LoadFile(Environment.CurrentDirectory + "\\" + line); | |||
foreach (Type type in assembly.GetTypes()) | |||
{ | |||
if (typeof(IJob).IsAssignableFrom(type) && type.IsClass) | |||
{ | |||
jobTypes.Add(type.FullName, assembly.GetName().Name); | |||
} | |||
} | |||
} | |||
foreach (var item in jobTypes) | |||
{ | |||
cboJobType.Items.Add(new JobType() { AssemblyName = item.Value, FullName = item.Key }); | |||
} | |||
//cboJobType.Items.AddRange(jobTypes.Values.ToArray<string>()); | |||
} | |||
public AddJobForm(TriggerNode node) | |||
: this() | |||
{ | |||
setTriggerData((CronTrigger)node.Trigger); | |||
setJobData(((JobNode)node.Parent.Parent).Detail); | |||
} | |||
private void setTriggerData(CronTrigger trigger) | |||
{ | |||
setTriggerType(); | |||
txtCronExpression.Text = trigger.CronExpressionString; | |||
txtTriggerDescription.Text = trigger.Description; | |||
txtTriggerGroup.Text = trigger.Group; | |||
txtTriggerName.Text = trigger.Name; | |||
} | |||
private void setJobData(JobDetail detail) | |||
{ | |||
setJobType(detail); | |||
txtJobDescription.Text = detail.Description; | |||
txtJobGroup.Text = detail.Group; | |||
txtJobName.Text = detail.Name; | |||
setJobDataMap(detail); | |||
} | |||
private void setJobDataMap(JobDetail detail) | |||
{ | |||
jobDataListView.Items.Clear(); | |||
foreach (var item in detail.JobDataMap.GetKeys()) | |||
{ | |||
jobDataListView.Items.Add(new ListViewItem(new string[] { item, detail.JobDataMap.Get(item).ToString() })); | |||
} | |||
} | |||
private void setJobType(JobDetail detail) | |||
{ | |||
cboJobType.SelectedItem = detail.JobType.FullName; | |||
} | |||
private void setTriggerType() | |||
{ | |||
//nothing to do right now | |||
} | |||
public JobDetail JobDetail { get; set; } | |||
public Trigger Trigger { get; set; } | |||
private void btnCancel_Click(object sender, EventArgs e) | |||
{ | |||
this.Close(); | |||
} | |||
private void btnAdd_Click(object sender, EventArgs e) | |||
{ | |||
JobDetail = getJobDetail(); | |||
Trigger = getTrigger(); | |||
Trigger.JobGroup = JobDetail.Group; | |||
Trigger.JobName = JobDetail.Name; | |||
this.Close(); | |||
} | |||
private JobDetail getJobDetail() | |||
{ | |||
JobDetail detail = new JobDetail(); | |||
detail.Description = txtJobDescription.Text; | |||
detail.Group = txtJobGroup.Text; | |||
detail.JobDataMap = getJobDataMap(); | |||
detail.JobType = getJobType(); | |||
detail.Name = txtJobName.Text; | |||
return detail; | |||
} | |||
private Trigger getTrigger() | |||
{ | |||
Trigger trigger; | |||
if (cboTriggerType.SelectedText == "Simple") | |||
{ | |||
trigger = new SimpleTrigger(); | |||
} | |||
else | |||
{ | |||
trigger = new CronTrigger(); | |||
((CronTrigger)trigger).CronExpressionString = txtCronExpression.Text; | |||
} | |||
trigger.Description = txtTriggerDescription.Text; | |||
trigger.Group = txtTriggerGroup.Text; | |||
trigger.Name = txtTriggerName.Text; | |||
return trigger; | |||
} | |||
private Type getJobType() | |||
{ | |||
JobType type = (JobType)cboJobType.SelectedItem; | |||
return Type.GetType(type.FullName + "," + type.AssemblyName, true); | |||
} | |||
private JobDataMap getJobDataMap() | |||
{ | |||
JobDataMap map = new JobDataMap(); | |||
foreach (ListViewItem item in jobDataListView.Items) | |||
{ | |||
map.Add(item.SubItems[0].Text, item.SubItems[1].Text); | |||
} | |||
return map; | |||
} | |||
private void btnAddKeyValue_Click(object sender, EventArgs e) | |||
{ | |||
ListViewItem item = new ListViewItem(new string[] { txtKey.Text, txtValue.Text }); | |||
jobDataListView.Items.Add(item); | |||
} | |||
private void btnDelete_Click(object sender, EventArgs e) | |||
{ | |||
foreach (ListViewItem item in jobDataListView.SelectedItems) | |||
{ | |||
jobDataListView.Items.Remove(item); | |||
} | |||
} | |||
} | |||
public partial class AddJobForm : Form | |||
{ | |||
public AddJobForm() | |||
{ | |||
InitializeComponent(); | |||
loadJobAssemblies(); | |||
cboTriggerType.Items.Add("Cron"); | |||
cboTriggerType.SelectedItem = "Cron"; | |||
if (cboJobType.SelectedText == "NativeJob") | |||
{ | |||
jobDataListView.Items.Add(new ListViewItem(new string[] { "consumeStreams", "true" })); | |||
jobDataListView.Items.Add(new ListViewItem(new string[] { "waitForProcess", "true" })); | |||
txtKey.Text = "command"; | |||
} | |||
} | |||
private void loadJobAssemblies() | |||
{ | |||
FileStream stream = File.OpenRead("JobAssemblies.txt"); | |||
StreamReader reader = new StreamReader(stream); | |||
string line; | |||
SortedList<string, string> jobTypes = new SortedList<string, string>(); | |||
while ((line = reader.ReadLine()) != null) | |||
{ | |||
Assembly assembly = Assembly.LoadFile(Environment.CurrentDirectory + "\\" + line); | |||
foreach (Type type in assembly.GetTypes()) | |||
{ | |||
if (typeof(IJob).IsAssignableFrom(type) && type.IsClass) | |||
{ | |||
jobTypes.Add(type.FullName, assembly.GetName().Name); | |||
} | |||
} | |||
} | |||
foreach (var item in jobTypes) | |||
{ | |||
cboJobType.Items.Add(new JobType() { AssemblyName = item.Value, FullName = item.Key }); | |||
} | |||
//cboJobType.Items.AddRange(jobTypes.Values.ToArray<string>()); | |||
} | |||
public AddJobForm(TriggerNode node) | |||
: this() | |||
{ | |||
setTriggerData((CronTriggerImpl)node.Trigger); | |||
setJobData(((JobNode)node.Parent.Parent).Detail); | |||
} | |||
private void setTriggerData(CronTriggerImpl trigger) | |||
{ | |||
setTriggerType(); | |||
txtCronExpression.Text = trigger.CronExpressionString; | |||
txtTriggerDescription.Text = trigger.Description; | |||
txtTriggerGroup.Text = trigger.Name.Group; | |||
txtTriggerName.Text = trigger.Name; | |||
} | |||
private void setJobData(IJobDetail detail) | |||
{ | |||
setJobType(detail); | |||
txtJobDescription.Text = detail.Description; | |||
txtJobGroup.Text = detail.Key.Group; | |||
txtJobName.Text = detail.Key.Name; | |||
setJobDataMap(detail); | |||
} | |||
private void setJobDataMap(IJobDetail detail) | |||
{ | |||
jobDataListView.Items.Clear(); | |||
foreach (var item in detail.JobDataMap.GetKeys()) | |||
{ | |||
jobDataListView.Items.Add(new ListViewItem(new string[] { item, detail.JobDataMap.Get(item).ToString() })); | |||
} | |||
} | |||
private void setJobType(IJobDetail detail) | |||
{ | |||
cboJobType.SelectedItem = detail.JobType.FullName; | |||
} | |||
private void setTriggerType() | |||
{ | |||
//nothing to do right now | |||
} | |||
public IJobDetail JobDetail { get; set; } | |||
public AbstractTrigger Trigger { get; set; } | |||
private void btnCancel_Click(object sender, EventArgs e) | |||
{ | |||
this.Close(); | |||
} | |||
private void btnAdd_Click(object sender, EventArgs e) | |||
{ | |||
JobDetail = getJobDetail(); | |||
AbstractTrigger trigger = getTrigger(); | |||
Trigger.JobGroup = JobDetail.Key.Group; | |||
Trigger.JobName = JobDetail.Key.Name; | |||
this.Close(); | |||
} | |||
private IJobDetail getJobDetail() | |||
{ | |||
IJobDetail detail = new IJobDetail(); | |||
detail.Description = txtJobDescription.Text; | |||
detail.Group = txtJobGroup.Text; | |||
detail.JobDataMap = getJobDataMap(); | |||
detail.JobType = getJobType(); | |||
detail.Name = txtJobName.Text; | |||
return detail; | |||
} | |||
private AbstractTrigger getTrigger() | |||
{ | |||
AbstractTrigger trigger; | |||
if (cboTriggerType.SelectedText == "Simple") | |||
{ | |||
trigger = new SimpleTrigger(); | |||
} | |||
else | |||
{ | |||
trigger = new CronTrigger(); | |||
((CronTrigger)trigger).CronExpressionString = txtCronExpression.Text; | |||
} | |||
trigger.Description = txtTriggerDescription.Text; | |||
trigger.Group = txtTriggerGroup.Text; | |||
trigger.Name = txtTriggerName.Text; | |||
return trigger; | |||
} | |||
private Type getJobType() | |||
{ | |||
JobType type = (JobType)cboJobType.SelectedItem; | |||
return Type.GetType(type.FullName + "," + type.AssemblyName, true); | |||
} | |||
private JobDataMap getJobDataMap() | |||
{ | |||
JobDataMap map = new JobDataMap(); | |||
foreach (ListViewItem item in jobDataListView.Items) | |||
{ | |||
map.Add(item.SubItems[0].Text, item.SubItems[1].Text); | |||
} | |||
return map; | |||
} | |||
private void btnAddKeyValue_Click(object sender, EventArgs e) | |||
{ | |||
ListViewItem item = new ListViewItem(new string[] { txtKey.Text, txtValue.Text }); | |||
jobDataListView.Items.Add(item); | |||
} | |||
private void btnDelete_Click(object sender, EventArgs e) | |||
{ | |||
foreach (ListViewItem item in jobDataListView.SelectedItems) | |||
{ | |||
jobDataListView.Items.Remove(item); | |||
} | |||
} | |||
} | |||
} |
@@ -7,48 +7,49 @@ using System.Linq; | |||
using System.Text; | |||
using System.Windows.Forms; | |||
using Quartz; | |||
using Quartz.Impl.Triggers; | |||
namespace ClickForensics.Quartz.Manager | |||
{ | |||
public partial class CronTriggerDisplay : UserControl | |||
{ | |||
public CronTriggerDisplay() | |||
{ | |||
InitializeComponent(); | |||
this.Load += new EventHandler(CronTriggerDisplay_Load); | |||
} | |||
public partial class CronTriggerDisplay : UserControl | |||
{ | |||
public CronTriggerDisplay() | |||
{ | |||
InitializeComponent(); | |||
this.Load += new EventHandler(CronTriggerDisplay_Load); | |||
} | |||
void CronTriggerDisplay_Load(object sender, EventArgs e) | |||
{ | |||
txtCronExpression.Text = _trigger.CronExpressionString; | |||
lblDescription.Text = _trigger.Description; | |||
lblGroup.Text = _trigger.Group; | |||
lblName.Text = _trigger.Name; | |||
if (_trigger.GetNextFireTimeUtc().HasValue) | |||
{ | |||
lblNextFireTime.Text = _trigger.GetNextFireTimeUtc().Value.ToLocalTime().ToString(); | |||
} | |||
else | |||
{ | |||
lblNextFireTime.Text = "Unknown"; | |||
} | |||
void CronTriggerDisplay_Load(object sender, EventArgs e) | |||
{ | |||
txtCronExpression.Text = _trigger.CronExpressionString; | |||
lblDescription.Text = _trigger.Description; | |||
lblGroup.Text = _trigger.Group; | |||
lblName.Text = _trigger.Name; | |||
if (_trigger.GetNextFireTimeUtc().HasValue) | |||
{ | |||
lblNextFireTime.Text = _trigger.GetNextFireTimeUtc().Value.ToLocalTime().ToString(); | |||
} | |||
else | |||
{ | |||
lblNextFireTime.Text = "Unknown"; | |||
} | |||
if (_trigger.GetPreviousFireTimeUtc().HasValue) | |||
{ | |||
lblPreviousFireTime.Text = _trigger.GetPreviousFireTimeUtc().Value.ToLocalTime().ToString(); | |||
} | |||
else | |||
{ | |||
lblPreviousFireTime.Text = "Unknown"; | |||
} | |||
} | |||
public CronTriggerDisplay(CronTrigger trigger) | |||
: this() | |||
{ | |||
_trigger = trigger; | |||
if (_trigger.GetPreviousFireTimeUtc().HasValue) | |||
{ | |||
lblPreviousFireTime.Text = _trigger.GetPreviousFireTimeUtc().Value.ToLocalTime().ToString(); | |||
} | |||
else | |||
{ | |||
lblPreviousFireTime.Text = "Unknown"; | |||
} | |||
} | |||
public CronTriggerDisplay(CronTriggerImpl trigger) | |||
: this() | |||
{ | |||
_trigger = trigger; | |||
} | |||
} | |||
private CronTrigger _trigger; | |||
} | |||
private CronTriggerImpl _trigger; | |||
} | |||
} |
@@ -4,18 +4,19 @@ using System.Linq; | |||
using System.Text; | |||
using System.Windows.Forms; | |||
using Quartz; | |||
using Quartz.Impl; | |||
namespace ClickForensics.Quartz.Manager | |||
{ | |||
public class JobNode : TreeNode | |||
{ | |||
public JobNode(JobDetail jobDetail) | |||
: base() | |||
{ | |||
this.Text = jobDetail.Name; | |||
Detail = jobDetail; | |||
} | |||
public JobDetail Detail { get; private set; } | |||
public class JobNode : TreeNode | |||
{ | |||
public JobNode(IJobDetail jobDetail) | |||
: base() | |||
{ | |||
this.Text = jobDetail.Key.Name; | |||
Detail = jobDetail; | |||
} | |||
public IJobDetail Detail { get; private set; } | |||
} | |||
} | |||
} |
@@ -11,370 +11,373 @@ using Quartz.Collection; | |||
using System.Net.Sockets; | |||
//using ClickForensics.Quartz.Jobs; | |||
using System.IO; | |||
using Quartz.Impl; | |||
using Quartz.Impl.Triggers; | |||
namespace ClickForensics.Quartz.Manager | |||
{ | |||
public partial class MainForm : Form | |||
{ | |||
public MainForm() | |||
{ | |||
InitializeComponent(); | |||
jobGroupsTreeView.AfterSelect += new TreeViewEventHandler(jobGroupsTreeView_AfterSelect); | |||
ctxScheduler.Opening += new CancelEventHandler(ctxScheduler_Opening); | |||
jobGroupsTreeView.MouseDown += new MouseEventHandler(jobGroupsTreeView_MouseDown); | |||
} | |||
void ctxScheduler_Opening(object sender, CancelEventArgs e) | |||
{ | |||
} | |||
void jobGroupsTreeView_AfterSelect(object sender, TreeViewEventArgs e) | |||
{ | |||
jobDetailsToggle(false); | |||
if (e.Node is TriggerNode || e.Node is JobNode) | |||
{ | |||
btnDeleteJob.Enabled = true; | |||
} | |||
else | |||
{ | |||
btnDeleteJob.Enabled = false; | |||
} | |||
if (e.Node is JobNode) | |||
{ | |||
btnRunJobNow.Enabled = true; | |||
pnlDetails.Controls.Add(new NativeJobDetailDisplay(((JobNode)e.Node).Detail)); | |||
jobDetailsToggle(true); | |||
} | |||
else | |||
{ | |||
btnRunJobNow.Enabled = false; | |||
} | |||
if (e.Node is TriggerNode) | |||
{ | |||
btnPause.Enabled = true; | |||
setPauseButtonText(); | |||
if (((TriggerNode)e.Node).Trigger is CronTrigger) | |||
{ | |||
pnlDetails.Controls.Add(new CronTriggerDisplay((CronTrigger)((TriggerNode)e.Node).Trigger)); | |||
jobDetailsToggle(true); | |||
} | |||
btnEdit.Enabled = true; | |||
} | |||
else | |||
{ | |||
btnEdit.Enabled = false; | |||
btnPause.Enabled = false; | |||
} | |||
} | |||
private void setPauseButtonText() | |||
{ | |||
TriggerNode node = (TriggerNode)jobGroupsTreeView.SelectedNode; | |||
string name = node.Trigger.Name; | |||
string group = node.Trigger.Group; | |||
if (Scheduler.GetScheduler().GetTriggerState(name, group) == TriggerState.Paused) | |||
{ | |||
btnPause.Text = "Resume"; | |||
} | |||
else | |||
{ | |||
btnPause.Text = "Pause"; | |||
} | |||
} | |||
private void connectToolStripMenuItem_Click(object sender, EventArgs e) | |||
{ | |||
using (ServerConnectForm form = new ServerConnectForm()) | |||
{ | |||
form.ShowDialog(); | |||
try | |||
{ | |||
Scheduler = new QuartzScheduler(form.Server, form.Port, form.Scheduler); | |||
serverConnectStatusLabel.Text = string.Format("Connected to {0}", Scheduler.Address); | |||
connectToolStripMenuItem.Enabled = false; | |||
jobsToolStripMenuItem.Enabled = true; | |||
loadJobGroups(); | |||
updateRunningJobs(); | |||
} | |||
catch (SocketException ex) | |||
{ | |||
ErrorDialog dialog = new ErrorDialog(); | |||
dialog.Message = string.Format("Unable to connect to scheduler {0} on {1}:{2}", form.Scheduler, form.Server, form.Port); | |||
dialog.Description = ex.Message; | |||
dialog.ShowDialog(); | |||
} | |||
form.Close(); | |||
} | |||
//loadGlobalTriggers(); | |||
} | |||
//private void loadGlobalTriggers() | |||
//{ | |||
// foreach (IJobListener jobListener in Scheduler.GetScheduler().GetJobDetail(null,null)..GlobalJobListeners) | |||
// { | |||
// globalTriggersListView.Items.Add(jobListener.Name); | |||
// } | |||
//} | |||
private void loadJobGroups() | |||
{ | |||
try | |||
{ | |||
this.Cursor = Cursors.WaitCursor; | |||
jobDetailsToggle(false); | |||
jobGroupsTreeView.Nodes.Clear(); | |||
SchedulerNode schedulerNode = new SchedulerNode(Scheduler); | |||
schedulerNode.ContextMenuStrip = ctxScheduler; | |||
jobGroupsTreeView.Nodes.Add(schedulerNode); | |||
TreeNode jobGroupsNode = schedulerNode.Nodes.Add("Job Groups"); | |||
string[] jobGroups = Scheduler.GetScheduler().JobGroupNames; | |||
foreach (string jobGroup in jobGroups) | |||
{ | |||
TreeNode jobGroupNode = jobGroupsNode.Nodes.Add(jobGroup); | |||
TreeNode jobsNode = jobGroupNode.Nodes.Add("Jobs"); | |||
addJobNodes(jobsNode); | |||
} | |||
jobGroupsTreeView.Nodes[0].Expand(); | |||
jobGroupsNode.Expand(); | |||
StripStatusLabel_Job_Groups.Text = DateTime.Now.ToString("yyyy.MM.dd HH:mm.ss"); | |||
} | |||
finally | |||
{ | |||
this.Cursor = Cursors.Default; | |||
} | |||
} | |||
private void jobDetailsToggle(bool isVisible) | |||
{ | |||
if (isVisible == false) | |||
{ | |||
pnlDetails.Controls.Clear(); | |||
} | |||
} | |||
void jobGroupsTreeView_MouseDown(object sender, MouseEventArgs e) | |||
{ | |||
if (e.Button == MouseButtons.Right) | |||
{ | |||
TreeNode node = jobGroupsTreeView.GetNodeAt(e.X, e.Y); | |||
if (node != null) | |||
{ | |||
jobGroupsTreeView.SelectedNode = node; | |||
ctxScheduler.Show(jobGroupsTreeView, e.Location); | |||
} | |||
} | |||
} | |||
//private void loadJobs() | |||
//{ | |||
// foreach (TreeNode node in jobGroupsTreeView.Nodes) | |||
// { | |||
// addJobNodes(node); | |||
// } | |||
//} | |||
private void addJobNodes(TreeNode node) | |||
{ | |||
string group = node.Parent.Text; | |||
string[] jobs = Scheduler.GetScheduler().GetJobNames(group); | |||
foreach (string jobName in jobs) | |||
{ | |||
try | |||
{ | |||
JobDetail detail = Scheduler.GetScheduler().GetJobDetail(jobName, group); | |||
JobNode jobNode = new JobNode(detail); | |||
node.Nodes.Add(jobNode); | |||
addTriggerNodes(jobNode); | |||
addListenerNodes(jobNode); | |||
} | |||
catch (Exception ex) | |||
{ | |||
//TODO: Do something useful with this exception. Most likely cause is the client does not have a copy of a given dll and can't load the type. | |||
} | |||
} | |||
} | |||
private void addListenerNodes(JobNode node) | |||
{ | |||
string jobName = node.Text; | |||
string jobGroupName = node.Parent.Text; | |||
string[] listenerNames = node.Detail.JobListenerNames; | |||
foreach (string listener in listenerNames) | |||
{ | |||
node.Text = string.Format("JL {0}", listenerNames); | |||
} | |||
//ISet set = Scheduler.GetScheduler().JobListenerNames; | |||
} | |||
private void addTriggerNodes(TreeNode treeNode) | |||
{ | |||
Trigger[] triggers = Scheduler.GetScheduler().GetTriggersOfJob(treeNode.Text, treeNode.Parent.Parent.Text); | |||
TreeNode triggersNode = treeNode.Nodes.Add("Triggers"); | |||
foreach (Trigger trigger in triggers) | |||
{ | |||
TriggerNode node = new TriggerNode(trigger); | |||
triggersNode.Nodes.Add(node); | |||
} | |||
} | |||
private void updateRunningJobs() | |||
{ | |||
try | |||
{ | |||
this.Cursor = Cursors.WaitCursor; | |||
timer_Refresh_Running_Jobs.Stop(); | |||
listView_RunningJobs.Items.Clear(); | |||
DataTable table = Scheduler.GetRunningJobs(); | |||
foreach (DataRow row in table.Rows) | |||
{ | |||
//JobName JobDuration | |||
ListViewItem item = new ListViewItem(new string[] { Convert.ToString(row["JobName"]), Convert.ToString(row["Runtime"]) }); | |||
listView_RunningJobs.Items.Add(item); | |||
} | |||
StripStatusLabel_Jobs_Refresh_date.Text = DateTime.Now.ToString("yyyy.MM.dd HH:mm.ss"); | |||
//reset the timer ( documentation not clear if .stop = restart @ 0 in timing, but changing the interval sure should do that. ) | |||
int timer_was = timer_Refresh_Running_Jobs.Interval; | |||
timer_Refresh_Running_Jobs.Interval = timer_was + 1; | |||
timer_Refresh_Running_Jobs.Interval = timer_was; | |||
timer_Refresh_Running_Jobs.Start(); | |||
} | |||
finally | |||
{ | |||
this.Cursor = Cursors.Default; | |||
} | |||
} | |||
public QuartzScheduler Scheduler { get; set; } | |||
private void addGlobalListenerToolStripMenuItem_Click(object sender, EventArgs e) | |||
{ | |||
AddListenerForm form = new AddListenerForm(); | |||
form.ListenerInterface = typeof(IJobListener); | |||
form.ShowDialog(); | |||
JobDataMap map = new JobDataMap(); | |||
map.Add("type", form.ListenerType); | |||
//Scheduler.ScheduleOneTimeJob(typeof(AddJobListenerJob), map, 0); | |||
loadJobGroups(); | |||
} | |||
private void addJobListenerToolStripMenuItem_Click(object sender, EventArgs e) | |||
{ | |||
TreeNode selectedNode = jobGroupsTreeView.SelectedNode; | |||
if (selectedNode != null && selectedNode is JobNode) | |||
{ | |||
AddListenerForm form = new AddListenerForm(); | |||
form.ListenerInterface = typeof(IJobListener); | |||
form.ShowDialog(); | |||
//JobHistoryListener listener = new JobHistoryListener(); | |||
//listener.Name = null; | |||
//((JobNode)selectedNode).Detail.AddJobListener(); | |||
} | |||
} | |||
private void addJobToolStripMenuItem_Click(object sender, EventArgs e) | |||
{ | |||
AddJobForm form = new AddJobForm(); | |||
form.ShowDialog(); | |||
if (form.JobDetail != null && form.Trigger != null) | |||
{ | |||
Scheduler.GetScheduler().ScheduleJob(form.JobDetail, form.Trigger); | |||
loadJobGroups(); | |||
} | |||
} | |||
private void btnRefreshRunningJobs_Click(object sender, EventArgs e) | |||
{ | |||
updateRunningJobs(); | |||
} | |||
private void btnRefreshJobGroups_Click(object sender, EventArgs e) | |||
{ | |||
loadJobGroups(); | |||
} | |||
private void btnRunJobNow_Click(object sender, EventArgs e) | |||
{ | |||
JobNode node = (JobNode)jobGroupsTreeView.SelectedNode; | |||
string job = node.Detail.Name; | |||
string group = node.Detail.Group; | |||
Scheduler.GetScheduler().TriggerJobWithVolatileTrigger(job, group); | |||
} | |||
private void btnDeleteJob_Click(object sender, EventArgs e) | |||
{ | |||
TreeNode selectedNode = jobGroupsTreeView.SelectedNode; | |||
if (selectedNode is JobNode) | |||
{ | |||
JobNode node = (JobNode)jobGroupsTreeView.SelectedNode; | |||
string job = node.Detail.Name; | |||
string group = node.Detail.Group; | |||
Scheduler.GetScheduler().DeleteJob(job, group); | |||
jobGroupsTreeView.SelectedNode.Remove(); | |||
} | |||
if (selectedNode is TriggerNode) | |||
{ | |||
Scheduler.GetScheduler().UnscheduleJob(((TriggerNode)selectedNode).Trigger.Name, ((TriggerNode)selectedNode).Trigger.Group); | |||
} | |||
//loadJobGroups(); | |||
} | |||
private void btnPause_Click(object sender, EventArgs e) | |||
{ | |||
TriggerNode node = (TriggerNode)jobGroupsTreeView.SelectedNode; | |||
string name = node.Trigger.Name; | |||
string group = node.Trigger.Group; | |||
if (Scheduler.GetScheduler().GetTriggerState(name, group) == TriggerState.Paused) | |||
{ | |||
Scheduler.GetScheduler().ResumeTrigger(name, group); | |||
} | |||
else | |||
{ | |||
Scheduler.GetScheduler().PauseTrigger(name, group); | |||
} | |||
setPauseButtonText(); | |||
} | |||
private void btnEdit_Click(object sender, EventArgs e) | |||
{ | |||
TriggerNode node = (TriggerNode)jobGroupsTreeView.SelectedNode; | |||
AddJobForm form = new AddJobForm(node); | |||
form.ShowDialog(); | |||
if (form.JobDetail != null && form.Trigger != null) | |||
{ | |||
Scheduler.GetScheduler().RescheduleJob(node.Trigger.Name, node.Trigger.Group, form.Trigger); | |||
loadJobGroups(); | |||
} | |||
} | |||
private void backupToolStripMenuItem_Click(object sender, EventArgs e) | |||
{ | |||
QuartzScheduler scheduler = ((SchedulerNode)((TreeView)((ContextMenuStrip)((ToolStripMenuItem)sender).Owner).SourceControl).SelectedNode).Scheduler; | |||
FileDialog dialog = new SaveFileDialog(); | |||
dialog.ShowDialog(); | |||
FileInfo file = new FileInfo(dialog.FileName); | |||
scheduler.BackupToFile(file); | |||
} | |||
private void timer_Refresh_Running_Jobs_Tick(object sender, EventArgs e) | |||
{ | |||
updateRunningJobs(); | |||
} | |||
} | |||
public partial class MainForm : Form | |||
{ | |||
public MainForm() | |||
{ | |||
InitializeComponent(); | |||
jobGroupsTreeView.AfterSelect += new TreeViewEventHandler(jobGroupsTreeView_AfterSelect); | |||
ctxScheduler.Opening += new CancelEventHandler(ctxScheduler_Opening); | |||
jobGroupsTreeView.MouseDown += new MouseEventHandler(jobGroupsTreeView_MouseDown); | |||
} | |||
void ctxScheduler_Opening(object sender, CancelEventArgs e) | |||
{ | |||
} | |||
void jobGroupsTreeView_AfterSelect(object sender, TreeViewEventArgs e) | |||
{ | |||
jobDetailsToggle(false); | |||
if (e.Node is TriggerNode || e.Node is JobNode) | |||
{ | |||
btnDeleteJob.Enabled = true; | |||
} | |||
else | |||
{ | |||
btnDeleteJob.Enabled = false; | |||
} | |||
if (e.Node is JobNode) | |||
{ | |||
btnRunJobNow.Enabled = true; | |||
pnlDetails.Controls.Add(new NativeJobDetailDisplay(((JobNode)e.Node).Detail)); | |||
jobDetailsToggle(true); | |||
} | |||
else | |||
{ | |||
btnRunJobNow.Enabled = false; | |||
} | |||
if (e.Node is TriggerNode) | |||
{ | |||
btnPause.Enabled = true; | |||
setPauseButtonText(); | |||
if (((TriggerNode)e.Node).Trigger is CronTrigger) | |||
{ | |||
pnlDetails.Controls.Add(new CronTriggerDisplay((CronTrigger)((TriggerNode)e.Node).Trigger)); | |||
jobDetailsToggle(true); | |||
} | |||
btnEdit.Enabled = true; | |||
} | |||
else | |||
{ | |||
btnEdit.Enabled = false; | |||
btnPause.Enabled = false; | |||
} | |||
} | |||
private void setPauseButtonText() | |||
{ | |||
TriggerNode node = (TriggerNode)jobGroupsTreeView.SelectedNode; | |||
string name = node.Trigger.Name; | |||
string group = node.Trigger.Group; | |||
if (Scheduler.GetScheduler().GetTriggerState(name, group) == TriggerState.Paused) | |||
{ | |||
btnPause.Text = "Resume"; | |||
} | |||
else | |||
{ | |||
btnPause.Text = "Pause"; | |||
} | |||
} | |||
private void connectToolStripMenuItem_Click(object sender, EventArgs e) | |||
{ | |||
using (ServerConnectForm form = new ServerConnectForm()) | |||
{ | |||
form.ShowDialog(); | |||
try | |||
{ | |||
Scheduler = new QuartzScheduler(form.Server, form.Port, form.Scheduler); | |||
serverConnectStatusLabel.Text = string.Format("Connected to {0}", Scheduler.Address); | |||
connectToolStripMenuItem.Enabled = false; | |||
jobsToolStripMenuItem.Enabled = true; | |||
loadJobGroups(); | |||
updateRunningJobs(); | |||
} | |||
catch (SocketException ex) | |||
{ | |||
ErrorDialog dialog = new ErrorDialog(); | |||
dialog.Message = string.Format("Unable to connect to scheduler {0} on {1}:{2}", form.Scheduler, form.Server, form.Port); | |||
dialog.Description = ex.Message; | |||
dialog.ShowDialog(); | |||
} | |||
form.Close(); | |||
} | |||
//loadGlobalTriggers(); | |||
} | |||
//private void loadGlobalTriggers() | |||
//{ | |||
// foreach (IJobListener jobListener in Scheduler.GetScheduler().GetJobDetail(null,null)..GlobalJobListeners) | |||
// { | |||
// globalTriggersListView.Items.Add(jobListener.Name); | |||
// } | |||
//} | |||
private void loadJobGroups() | |||
{ | |||
try | |||
{ | |||
this.Cursor = Cursors.WaitCursor; | |||
jobDetailsToggle(false); | |||
jobGroupsTreeView.Nodes.Clear(); | |||
SchedulerNode schedulerNode = new SchedulerNode(Scheduler); | |||
schedulerNode.ContextMenuStrip = ctxScheduler; | |||
jobGroupsTreeView.Nodes.Add(schedulerNode); | |||
TreeNode jobGroupsNode = schedulerNode.Nodes.Add("Job Groups"); | |||
string[] jobGroups = Scheduler.GetScheduler().JobGroupNames; | |||
foreach (string jobGroup in jobGroups) | |||
{ | |||
TreeNode jobGroupNode = jobGroupsNode.Nodes.Add(jobGroup); | |||
TreeNode jobsNode = jobGroupNode.Nodes.Add("Jobs"); | |||
addJobNodes(jobsNode); | |||
} | |||
jobGroupsTreeView.Nodes[0].Expand(); | |||
jobGroupsNode.Expand(); | |||
StripStatusLabel_Job_Groups.Text = DateTime.Now.ToString("yyyy.MM.dd HH:mm.ss"); | |||
} | |||
finally | |||
{ | |||
this.Cursor = Cursors.Default; | |||
} | |||
} | |||
private void jobDetailsToggle(bool isVisible) | |||
{ | |||
if (isVisible == false) | |||
{ | |||
pnlDetails.Controls.Clear(); | |||
} | |||
} | |||
void jobGroupsTreeView_MouseDown(object sender, MouseEventArgs e) | |||
{ | |||
if (e.Button == MouseButtons.Right) | |||
{ | |||
TreeNode node = jobGroupsTreeView.GetNodeAt(e.X, e.Y); | |||
if (node != null) | |||
{ | |||
jobGroupsTreeView.SelectedNode = node; | |||
ctxScheduler.Show(jobGroupsTreeView, e.Location); | |||
} | |||
} | |||
} | |||
//private void loadJobs() | |||
//{ | |||
// foreach (TreeNode node in jobGroupsTreeView.Nodes) | |||
// { | |||
// addJobNodes(node); | |||
// } | |||
//} | |||
private void addJobNodes(TreeNode node) | |||
{ | |||
string group = node.Parent.Text; | |||
string[] jobs = Scheduler.GetScheduler().GetJobNames(group); | |||
foreach (string jobName in jobs) | |||
{ | |||
try | |||
{ | |||
IJobDetail detail = Scheduler.GetScheduler().GetJobDetail(new JobKey(jobName, group)); | |||
JobNode jobNode = new JobNode(detail); | |||
node.Nodes.Add(jobNode); | |||
addTriggerNodes(jobNode); | |||
addListenerNodes(jobNode); | |||
} | |||
catch (Exception ex) | |||
{ | |||
//TODO: Do something useful with this exception. Most likely cause is the client does not have a copy of a given dll and can't load the type. | |||
} | |||
} | |||
} | |||
private void addListenerNodes(JobNode node) | |||
{ | |||
string jobName = node.Text; | |||
string jobGroupName = node.Parent.Text; | |||
//TODO: see joblistenermanager get listeners | |||
//string[] listenerNames = node.Detail.JobListenerNames; | |||
//foreach (string listener in listenerNames) | |||
//{ | |||
// node.Text = string.Format("JL {0}", listenerNames); | |||
//} | |||
//ISet set = Scheduler.GetScheduler().JobListenerNames; | |||
} | |||
private void addTriggerNodes(TreeNode treeNode) | |||
{ | |||
AbstractTrigger[] triggers = Scheduler.GetScheduler().GetTriggersOfJob(treeNode.Text, treeNode.Parent.Parent.Text); | |||
TreeNode triggersNode = treeNode.Nodes.Add("Triggers"); | |||
foreach (AbstractTrigger trigger in triggers) | |||
{ | |||
TriggerNode node = new TriggerNode(trigger); | |||
triggersNode.Nodes.Add(node); | |||
} | |||
} | |||
private void updateRunningJobs() | |||
{ | |||
try | |||
{ | |||
this.Cursor = Cursors.WaitCursor; | |||
timer_Refresh_Running_Jobs.Stop(); | |||
listView_RunningJobs.Items.Clear(); | |||
DataTable table = Scheduler.GetRunningJobs(); | |||
foreach (DataRow row in table.Rows) | |||
{ | |||
//JobName JobDuration | |||
ListViewItem item = new ListViewItem(new string[] { Convert.ToString(row["JobName"]), Convert.ToString(row["Runtime"]) }); | |||
listView_RunningJobs.Items.Add(item); | |||
} | |||
StripStatusLabel_Jobs_Refresh_date.Text = DateTime.Now.ToString("yyyy.MM.dd HH:mm.ss"); | |||
//reset the timer ( documentation not clear if .stop = restart @ 0 in timing, but changing the interval sure should do that. ) | |||
int timer_was = timer_Refresh_Running_Jobs.Interval; | |||
timer_Refresh_Running_Jobs.Interval = timer_was + 1; | |||
timer_Refresh_Running_Jobs.Interval = timer_was; | |||
timer_Refresh_Running_Jobs.Start(); | |||
} | |||
finally | |||
{ | |||
this.Cursor = Cursors.Default; | |||
} | |||
} | |||
public QuartzScheduler Scheduler { get; set; } | |||
private void addGlobalListenerToolStripMenuItem_Click(object sender, EventArgs e) | |||
{ | |||
AddListenerForm form = new AddListenerForm(); | |||
form.ListenerInterface = typeof(IJobListener); | |||
form.ShowDialog(); | |||
JobDataMap map = new JobDataMap(); | |||
map.Add("type", form.ListenerType); | |||
//Scheduler.ScheduleOneTimeJob(typeof(AddJobListenerJob), map, 0); | |||
loadJobGroups(); | |||
} | |||
private void addJobListenerToolStripMenuItem_Click(object sender, EventArgs e) | |||
{ | |||
TreeNode selectedNode = jobGroupsTreeView.SelectedNode; | |||
if (selectedNode != null && selectedNode is JobNode) | |||
{ | |||
AddListenerForm form = new AddListenerForm(); | |||
form.ListenerInterface = typeof(IJobListener); | |||
form.ShowDialog(); | |||
//JobHistoryListener listener = new JobHistoryListener(); | |||
//listener.Name = null; | |||
//((JobNode)selectedNode).Detail.AddJobListener(); | |||
} | |||
} | |||
private void addJobToolStripMenuItem_Click(object sender, EventArgs e) | |||
{ | |||
AddJobForm form = new AddJobForm(); | |||
form.ShowDialog(); | |||
if (form.JobDetail != null && form.Trigger != null) | |||
{ | |||
Scheduler.GetScheduler().ScheduleJob(form.JobDetail, form.Trigger); | |||
loadJobGroups(); | |||
} | |||
} | |||
private void btnRefreshRunningJobs_Click(object sender, EventArgs e) | |||
{ | |||
updateRunningJobs(); | |||
} | |||
private void btnRefreshJobGroups_Click(object sender, EventArgs e) | |||
{ | |||
loadJobGroups(); | |||
} | |||
private void btnRunJobNow_Click(object sender, EventArgs e) | |||
{ | |||
JobNode node = (JobNode)jobGroupsTreeView.SelectedNode; | |||
string job = node.Detail.Name; | |||
string group = node.Detail.Group; | |||
Scheduler.GetScheduler().TriggerJobWithVolatileTrigger(job, group); | |||
} | |||
private void btnDeleteJob_Click(object sender, EventArgs e) | |||
{ | |||
TreeNode selectedNode = jobGroupsTreeView.SelectedNode; | |||
if (selectedNode is JobNode) | |||
{ | |||
JobNode node = (JobNode)jobGroupsTreeView.SelectedNode; | |||
string job = node.Detail.Name; | |||
string group = node.Detail.Group; | |||
Scheduler.GetScheduler().DeleteJob(job, group); | |||
jobGroupsTreeView.SelectedNode.Remove(); | |||
} | |||
if (selectedNode is TriggerNode) | |||
{ | |||
Scheduler.GetScheduler().UnscheduleJob(((TriggerNode)selectedNode).Trigger.Name, ((TriggerNode)selectedNode).Trigger.Group); | |||
} | |||
//loadJobGroups(); | |||
} | |||
private void btnPause_Click(object sender, EventArgs e) | |||
{ | |||
TriggerNode node = (TriggerNode)jobGroupsTreeView.SelectedNode; | |||
string name = node.Trigger.Name; | |||
string group = node.Trigger.Group; | |||
if (Scheduler.GetScheduler().GetTriggerState(name, group) == TriggerState.Paused) | |||
{ | |||
Scheduler.GetScheduler().ResumeTrigger(name, group); | |||
} | |||
else | |||
{ | |||
Scheduler.GetScheduler().PauseTrigger(name, group); | |||
} | |||
setPauseButtonText(); | |||
} | |||
private void btnEdit_Click(object sender, EventArgs e) | |||
{ | |||
TriggerNode node = (TriggerNode)jobGroupsTreeView.SelectedNode; | |||
AddJobForm form = new AddJobForm(node); | |||
form.ShowDialog(); | |||
if (form.JobDetail != null && form.Trigger != null) | |||
{ | |||
Scheduler.GetScheduler().RescheduleJob(node.Trigger.Name, node.Trigger.Group, form.Trigger); | |||
loadJobGroups(); | |||
} | |||
} | |||
private void backupToolStripMenuItem_Click(object sender, EventArgs e) | |||
{ | |||
QuartzScheduler scheduler = ((SchedulerNode)((TreeView)((ContextMenuStrip)((ToolStripMenuItem)sender).Owner).SourceControl).SelectedNode).Scheduler; | |||
FileDialog dialog = new SaveFileDialog(); | |||
dialog.ShowDialog(); | |||
FileInfo file = new FileInfo(dialog.FileName); | |||
scheduler.BackupToFile(file); | |||
} | |||
private void timer_Refresh_Running_Jobs_Tick(object sender, EventArgs e) | |||
{ | |||
updateRunningJobs(); | |||
} | |||
} | |||
} |
@@ -7,6 +7,7 @@ using System.Linq; | |||
using System.Text; | |||
using System.Windows.Forms; | |||
using Quartz; | |||
using Quartz.Impl; | |||
namespace ClickForensics.Quartz.Manager | |||
{ | |||
@@ -21,8 +22,8 @@ namespace ClickForensics.Quartz.Manager | |||
void NativeJobDetailDisplay_Load(object sender, EventArgs e) | |||
{ | |||
lblDescription.Text = _detail.Description; | |||
lblGroup.Text = _detail.Group; | |||
lblName.Text = _detail.Name; | |||
lblGroup.Text = _detail.Key.Group; | |||
lblName.Text = _detail.Key.Name; | |||
loadJobDataMap(); | |||
} | |||
@@ -33,12 +34,12 @@ namespace ClickForensics.Quartz.Manager | |||
jobDataListView.Items.Add(new ListViewItem(new string[] { item, _detail.JobDataMap.Get(item).ToString() })); | |||
} | |||
} | |||
public NativeJobDetailDisplay(JobDetail detail) | |||
public NativeJobDetailDisplay(IJobDetail detail) | |||
: this() | |||
{ | |||
_detail = detail; | |||
} | |||
private JobDetail _detail; | |||
private IJobDetail _detail; | |||
} | |||
} |
@@ -11,301 +11,305 @@ using System.Collections; | |||
using System.Windows.Forms; | |||
using System.IO; | |||
using System.Xml.Linq; | |||
using Quartz.Impl.Matchers; | |||
using Quartz.Impl.Triggers; | |||
using Quartz.Util; | |||
namespace ClickForensics.Quartz.Manager | |||
{ | |||
public class QuartzScheduler | |||
{ | |||
public QuartzScheduler(string server, int port, string scheduler) | |||
{ | |||
Address = string.Format("tcp://{0}:{1}/{2}", server, port, scheduler); | |||
_schedulerFactory = new StdSchedulerFactory(getProperties(Address)); | |||
public class QuartzScheduler | |||
{ | |||
public QuartzScheduler(string server, int port, string scheduler) | |||
{ | |||
Address = string.Format("tcp://{0}:{1}/{2}", server, port, scheduler); | |||
_schedulerFactory = new StdSchedulerFactory(getProperties(Address)); | |||
try | |||
{ | |||
_scheduler = _schedulerFactory.GetScheduler(); | |||
} | |||
catch (SchedulerException se) | |||
{ | |||
MessageBox.Show("Unable to connect to the specified server", "Connection Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); | |||
} | |||
} | |||
public string Address { get; private set; } | |||
private NameValueCollection getProperties(string address) | |||
{ | |||
NameValueCollection properties = new NameValueCollection(); | |||
properties["quartz.scheduler.instanceName"] = "RemoteClient"; | |||
properties["quartz.scheduler.proxy"] = "true"; | |||
properties["quartz.threadPool.threadCount"] = "0"; | |||
properties["quartz.scheduler.proxy.address"] = address; | |||
return properties; | |||
} | |||
public IScheduler GetScheduler() | |||
{ | |||
return _scheduler; | |||
} | |||
public DataTable GetJobs() | |||
{ | |||
DataTable table = new DataTable(); | |||
table.Columns.Add("GroupName"); | |||
table.Columns.Add("JobName"); | |||
table.Columns.Add("JobDescription"); | |||
table.Columns.Add("TriggerName"); | |||
table.Columns.Add("TriggerGroupName"); | |||
table.Columns.Add("TriggerType"); | |||
table.Columns.Add("TriggerState"); | |||
table.Columns.Add("NextFireTime"); | |||
table.Columns.Add("PreviousFireTime"); | |||
string[] jobGroups = GetScheduler().JobGroupNames; | |||
foreach (string group in jobGroups) | |||
{ | |||
string[] jobNames = GetScheduler().GetJobNames(group); | |||
foreach (string job in jobNames) | |||
{ | |||
JobDetail detail = GetScheduler().GetJobDetail(job, group); | |||
Trigger[] triggers = GetScheduler().GetTriggersOfJob(job, group); | |||
foreach (Trigger trigger in triggers) | |||
{ | |||
DataRow row = table.NewRow(); | |||
row["GroupName"] = group; | |||
row["JobName"] = job; | |||
row["JobDescription"] = detail.Description; | |||
row["TriggerName"] = trigger.Name; | |||
row["TriggerGroupName"] = trigger.Group; | |||
row["TriggerType"] = trigger.GetType().Name; | |||
row["TriggerState"] = GetScheduler().GetTriggerState(trigger.Name, trigger.Group); | |||
DateTime? nextFireTime = trigger.GetNextFireTimeUtc(); | |||
if (nextFireTime != null) | |||
{ | |||
row["NextFireTime"] = TimeZone.CurrentTimeZone.ToLocalTime((DateTime)nextFireTime); | |||
} | |||
try | |||
{ | |||
_scheduler = _schedulerFactory.GetScheduler(); | |||
} | |||
catch (SchedulerException se) | |||
{ | |||
MessageBox.Show("Unable to connect to the specified server", "Connection Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); | |||
} | |||
} | |||
public string Address { get; private set; } | |||
private NameValueCollection getProperties(string address) | |||
{ | |||
NameValueCollection properties = new NameValueCollection(); | |||
properties["quartz.scheduler.instanceName"] = "RemoteClient"; | |||
properties["quartz.scheduler.proxy"] = "true"; | |||
properties["quartz.threadPool.threadCount"] = "0"; | |||
properties["quartz.scheduler.proxy.address"] = address; | |||
return properties; | |||
} | |||
public IScheduler GetScheduler() | |||
{ | |||
return _scheduler; | |||
} | |||
public DataTable GetJobs() | |||
{ | |||
DataTable table = new DataTable(); | |||
table.Columns.Add("GroupName"); | |||
table.Columns.Add("JobName"); | |||
table.Columns.Add("JobDescription"); | |||
table.Columns.Add("TriggerName"); | |||
table.Columns.Add("TriggerGroupName"); | |||
table.Columns.Add("TriggerType"); | |||
table.Columns.Add("TriggerState"); | |||
table.Columns.Add("NextFireTime"); | |||
table.Columns.Add("PreviousFireTime"); | |||
var jobGroups = GetScheduler().GetJobGroupNames(); | |||
foreach (string group in jobGroups) | |||
{ | |||
var groupMatcher = GroupMatcher<JobKey>.GroupContains(group); | |||
var jobKeys = GetScheduler().GetJobKeys(groupMatcher); | |||
foreach (var jobKey in jobKeys) | |||
{ | |||
var detail = GetScheduler().GetJobDetail(jobKey); | |||
var triggers = GetScheduler().GetTriggersOfJob(jobKey); | |||
foreach (ITrigger trigger in triggers) | |||
{ | |||
DataRow row = table.NewRow(); | |||
row["GroupName"] = group; | |||
row["JobName"] = jobKey.Name; | |||
row["JobDescription"] = detail.Description; | |||
row["TriggerName"] = trigger.Key.Name; | |||
row["TriggerGroupName"] = trigger.Key.Group; | |||
row["TriggerType"] = trigger.GetType().Name; | |||
row["TriggerState"] = GetScheduler().GetTriggerState(trigger.Key); | |||
DateTimeOffset? nextFireTime = trigger.GetNextFireTimeUtc(); | |||
if (nextFireTime.HasValue) | |||
{ | |||
row["NextFireTime"] = TimeZone.CurrentTimeZone.ToLocalTime(nextFireTime.Value.DateTime); | |||
} | |||
DateTime? previousFireTime = trigger.GetPreviousFireTimeUtc(); | |||
if (previousFireTime != null) | |||
{ | |||
row["PreviousFireTime"] = TimeZone.CurrentTimeZone.ToLocalTime((DateTime)previousFireTime); | |||
} | |||
DateTimeOffset? previousFireTime = trigger.GetPreviousFireTimeUtc(); | |||
if (previousFireTime.HasValue) | |||
{ | |||
row["PreviousFireTime"] = TimeZone.CurrentTimeZone.ToLocalTime(previousFireTime.Value.DateTime); | |||
} | |||
table.Rows.Add(row); | |||
} | |||
} | |||
} | |||
return table; | |||
} | |||
table.Rows.Add(row); | |||
} | |||
} | |||
} | |||
return table; | |||
} | |||
public void ScheduleOneTimeJob(Type jobType, JobDataMap dataMap, int clientID) | |||
{ | |||
string name = string.Format("{0}-{1}", jobType.Name, clientID); | |||
string group = clientID.ToString(); | |||
JobDetail jobDetail = new JobDetail(name, group, jobType); | |||
jobDetail.Description = "One time job"; | |||
jobDetail.Durable = false; | |||
jobDetail.Group = group; | |||
jobDetail.JobDataMap = dataMap; | |||
jobDetail.JobType = jobType; | |||
jobDetail.Name = name; | |||
jobDetail.Volatile = true; | |||
SimpleTrigger trigger = new SimpleTrigger(); | |||
trigger.Name = name; | |||
trigger.Group = group; | |||
trigger.StartTimeUtc = DateTime.UtcNow; | |||
trigger.RepeatCount = 0; | |||
trigger.RepeatInterval = TimeSpan.Zero; | |||
GetScheduler().ScheduleJob(jobDetail, trigger); | |||
} | |||
public void ScheduleOneTimeJob(Type jobType, JobDataMap dataMap, int clientID) | |||
{ | |||
string name = string.Format("{0}-{1}", jobType.Name, clientID); | |||
string group = clientID.ToString(); | |||
IJobDetail jobDetail = JobBuilder. | |||
NewJob(). | |||
OfType(jobType). | |||
WithIdentity(name, group). | |||
WithDescription("One time job"). | |||
UsingJobData(dataMap).Build(); | |||
ITrigger trigger = TriggerBuilder. | |||
Create(). | |||
ForJob(jobDetail). | |||
WithIdentity(name, group). | |||
WithSchedule(SimpleScheduleBuilder.Create().WithRepeatCount(0).WithInterval(TimeSpan.Zero)). | |||
StartNow().Build(); | |||
GetScheduler().ScheduleJob(jobDetail, trigger); | |||
} | |||
private ISchedulerFactory _schedulerFactory; | |||
private ISchedulerFactory _schedulerFactory; | |||
private IScheduler _scheduler; | |||
private IScheduler _scheduler; | |||
public DataTable GetRunningJobs() | |||
{ | |||
DataTable table = new DataTable(); | |||
table.Columns.Add("JobName", typeof(string)); | |||
table.Columns.Add("RunTime", typeof(int)); | |||
try | |||
{ | |||
IList jobs = GetScheduler().GetCurrentlyExecutingJobs(); | |||
foreach (JobExecutionContext context in jobs) | |||
{ | |||
DataRow row = table.NewRow(); | |||
row["JobName"] = context.JobDetail.Name; | |||
row["RunTime"] = (DateTime.Now.ToUniversalTime() - (DateTime)context.FireTimeUtc).TotalMinutes; | |||
table.Rows.Add(row); | |||
} | |||
} | |||
catch (Exception ex) | |||
{ | |||
//TODO: Let the user know we couldn't load the running jobs. | |||
} | |||
public DataTable GetRunningJobs() | |||
{ | |||
DataTable table = new DataTable(); | |||
table.Columns.Add("JobName", typeof(string)); | |||
table.Columns.Add("RunTime", typeof(int)); | |||
try | |||
{ | |||
var contexts = GetScheduler().GetCurrentlyExecutingJobs(); | |||
foreach (var context in contexts) | |||
{ | |||
DataRow row = table.NewRow(); | |||
row["JobName"] = context.JobDetail.Key.Name; | |||
row["RunTime"] = (DateTime.Now.ToUniversalTime() - ((DateTimeOffset)context.FireTimeUtc).DateTime).TotalMinutes; | |||
table.Rows.Add(row); | |||
} | |||
} | |||
catch (Exception ex) | |||
{ | |||
//TODO: Let the user know we couldn't load the running jobs. | |||
} | |||
return table; | |||
} | |||
return table; | |||
} | |||
public void BackupToFile(System.IO.FileInfo file) | |||
{ | |||
IScheduler scheduler = GetScheduler(); | |||
string[] jobGroupNames = scheduler.JobGroupNames; | |||
List<JobDetail> jobDetails = new List<JobDetail>(); | |||
foreach (var jobGroup in jobGroupNames) | |||
{ | |||
string[] jobNames = scheduler.GetJobNames(jobGroup); | |||
foreach (var jobName in jobNames) | |||
{ | |||
jobDetails.Add(scheduler.GetJobDetail(jobName, jobGroup)); | |||
} | |||
} | |||
writeToFile(file, jobDetails); | |||
public void BackupToFile(System.IO.FileInfo file) | |||
{ | |||
IScheduler scheduler = GetScheduler(); | |||
string[] jobGroupNames = scheduler.JobGroupNames; | |||
List<IJobDetail> jobDetails = new List<IJobDetail>(); | |||
foreach (var jobGroup in jobGroupNames) | |||
{ | |||
string[] jobNames = scheduler.GetJobNames(jobGroup); | |||
foreach (var jobName in jobNames) | |||
{ | |||
jobDetails.Add(scheduler.GetJobDetail(jobName, jobGroup)); | |||
} | |||
} | |||
writeToFile(file, jobDetails); | |||
} | |||
} | |||
private void writeToFile(System.IO.FileInfo file, List<JobDetail> jobDetails) | |||
{ | |||
using (StreamWriter writer = file.CreateText()) | |||
{ | |||
XNamespace ns = "http://quartznet.sourceforge.net/JobSchedulingData"; | |||
XDocument doc = new XDocument(new XDeclaration("1.0", "UTF-8", "yes") | |||
, new XElement(ns + "quartz" | |||
, new XAttribute(XNamespace.Xmlns + "xsi", "http://www.w3.org/2001/XMLSchema-instance") | |||
, new XAttribute("version", "1.0") | |||
, new XAttribute("overwrite-existing-jobs", "true") | |||
) | |||
); | |||
foreach (JobDetail detail in jobDetails) | |||
{ | |||
doc.Root.Add( | |||
new XElement(ns + "job" | |||
, new XElement(ns + "job-detail" | |||
, new XElement(ns + "name", detail.Name) | |||
, new XElement(ns + "group", detail.Group) | |||
, new XElement(ns + "description", detail.Description) | |||
, new XElement(ns + "job-type", detail.JobType.FullName + "," + detail.JobType.Assembly.FullName) | |||
, new XElement(ns + "volatile", detail.Volatile) | |||
, new XElement(ns + "durable", detail.Durable) | |||
, new XElement(ns + "recover", detail.RequestsRecovery) | |||
, getJobDataMap(ns, detail.JobDataMap) | |||
) | |||
, getTriggers(ns, detail) | |||
) | |||
); | |||
} | |||
writer.Write(doc); | |||
writer.Flush(); | |||
writer.Close(); | |||
} | |||
} | |||
private void writeToFile(System.IO.FileInfo file, List<IJobDetail> jobDetails) | |||
{ | |||
using (StreamWriter writer = file.CreateText()) | |||
{ | |||
XNamespace ns = "http://quartznet.sourceforge.net/JobSchedulingData"; | |||
XDocument doc = new XDocument(new XDeclaration("1.0", "UTF-8", "yes") | |||
, new XElement(ns + "quartz" | |||
, new XAttribute(XNamespace.Xmlns + "xsi", "http://www.w3.org/2001/XMLSchema-instance") | |||
, new XAttribute("version", "1.0") | |||
, new XAttribute("overwrite-existing-jobs", "true") | |||
) | |||
); | |||
foreach (JobDetail detail in jobDetails) | |||
{ | |||
doc.Root.Add( | |||
new XElement(ns + "job" | |||
, new XElement(ns + "job-detail" | |||
, new XElement(ns + "name", detail.Name) | |||
, new XElement(ns + "group", detail.Group) | |||
, new XElement(ns + "description", detail.Description) | |||
, new XElement(ns + "job-type", detail.JobType.FullName + "," + detail.JobType.Assembly.FullName) | |||
, new XElement(ns + "volatile", detail.Volatile) | |||
, new XElement(ns + "durable", detail.Durable) | |||
, new XElement(ns + "recover", detail.RequestsRecovery) | |||
, getJobDataMap(ns, detail.JobDataMap) | |||
) | |||
, getTriggers(ns, detail) | |||
) | |||
); | |||
} | |||
writer.Write(doc); | |||
writer.Flush(); | |||
writer.Close(); | |||
} | |||
} | |||
private XElement getJobDataMap(XNamespace ns, JobDataMap jobDataMap) | |||
{ | |||
XElement map = new XElement(ns + "job-data-map"); | |||
foreach (var key in jobDataMap.GetKeys()) | |||
{ | |||
map.Add(new XElement(ns + "entry" | |||
, new XElement(ns + "key", key) | |||
, new XElement(ns + "value", jobDataMap[key]) | |||
) | |||
); | |||
} | |||
private XElement getJobDataMap(XNamespace ns, JobDataMap jobDataMap) | |||
{ | |||
XElement map = new XElement(ns + "job-data-map"); | |||
foreach (var key in jobDataMap.GetKeys()) | |||
{ | |||
map.Add(new XElement(ns + "entry" | |||
, new XElement(ns + "key", key) | |||
, new XElement(ns + "value", jobDataMap[key]) | |||
) | |||
); | |||
} | |||
return map; | |||
} | |||
return map; | |||
} | |||
private XElement[] getTriggers(XNamespace ns, JobDetail detail) | |||
{ | |||
Trigger[] triggers = _scheduler.GetTriggersOfJob(detail.Name, detail.Group); | |||
XElement[] elements = new XElement[triggers.Length]; | |||
for (int i = 0; i < triggers.Length; i++) | |||
{ | |||
elements[i] = new XElement(ns + "trigger"); | |||
if (triggers[i] is SimpleTrigger) | |||
{ | |||
elements[i].Add(getSimpleTrigger(ns, (SimpleTrigger)triggers[i])); | |||
} | |||
else if (triggers[i] is CronTrigger) | |||
{ | |||
elements[i].Add(getCronTrigger(ns, (CronTrigger)triggers[i])); | |||
} | |||
} | |||
return elements; | |||
} | |||
private XElement[] getTriggers(XNamespace ns, IJobDetail detail) | |||
{ | |||
var triggers = _scheduler.GetTriggersOfJob(detail.Key); | |||
XElement[] elements = new XElement[triggers.Count]; | |||
int i = 0; | |||
foreach (var trigger in triggers) | |||
{ | |||
elements[i] = new XElement(ns + "trigger"); | |||
if (triggers[i] is SimpleTriggerImpl) | |||
{ | |||
elements[i].Add(getSimpleTrigger(ns, (SimpleTriggerImpl)triggers[i])); | |||
} | |||
else if (triggers[i] is CronTriggerImpl) | |||
{ | |||
elements[i].Add(getCronTrigger(ns, (CronTriggerImpl)triggers[i])); | |||
} | |||
i++; | |||
} | |||
return elements; | |||
} | |||
private XElement getCronTrigger(XNamespace ns, CronTrigger trigger) | |||
{ | |||
XElement cronTrigger = new XElement(ns + "cron"); | |||
addCommonTriggerData(ns, cronTrigger, trigger); | |||
cronTrigger.Add( | |||
new XElement(ns + "cron-expression", trigger.CronExpressionString) | |||
); | |||
return cronTrigger; | |||
} | |||
private XElement getCronTrigger(XNamespace ns, CronTriggerImpl trigger) | |||
{ | |||
XElement cronTrigger = new XElement(ns + "cron"); | |||
addCommonTriggerData(ns, cronTrigger, trigger); | |||
cronTrigger.Add( | |||
new XElement(ns + "cron-expression", trigger.CronExpressionString) | |||
); | |||
return cronTrigger; | |||
} | |||
private void addCommonTriggerData(XNamespace ns, XElement rootTriggerElement, Trigger trigger) | |||
{ | |||
rootTriggerElement.Add( | |||
new XElement(ns + "name", trigger.Name) | |||
, new XElement(ns + "group", trigger.Group) | |||
, new XElement(ns + "description", trigger.Description) | |||
, new XElement(ns + "misfire-instruction", getMisfireInstructionText(trigger)) | |||
, new XElement(ns + "volatile", trigger.Volatile) | |||
, new XElement(ns + "job-name", trigger.JobName) | |||
, new XElement(ns + "job-group", trigger.JobGroup) | |||
); | |||
} | |||
private void addCommonTriggerData(XNamespace ns, XElement rootTriggerElement, AbstractTrigger trigger) | |||
{ | |||
rootTriggerElement.Add( | |||
new XElement(ns + "name", trigger.Name) | |||
, new XElement(ns + "group", trigger.Group) | |||
, new XElement(ns + "description", trigger.Description) | |||
, new XElement(ns + "misfire-instruction", getMisfireInstructionText(trigger)) | |||
//, new XElement(ns + "volatile", trigger.Volatile) | |||
, new XElement(ns + "job-name", trigger.JobName) | |||
, new XElement(ns + "job-group", trigger.JobGroup) | |||
); | |||
} | |||
private string getMisfireInstructionText(Trigger trigger) | |||
{ | |||
if (trigger is CronTrigger) | |||
{ | |||
return getCronTriggerMisfireInstructionText(trigger.MisfireInstruction); | |||
} | |||
return getSimpleTriggerMisfireInstructionText(trigger.MisfireInstruction); | |||
} | |||
private string getMisfireInstructionText(AbstractTrigger trigger) | |||
{ | |||
if (trigger is CronTriggerImpl) | |||
{ | |||
return getCronTriggerMisfireInstructionText(trigger.MisfireInstruction); | |||
} | |||
return getSimpleTriggerMisfireInstructionText(trigger.MisfireInstruction); | |||
} | |||
private string getSimpleTriggerMisfireInstructionText(int misfireInstruction) | |||
{ | |||
switch (misfireInstruction) | |||
{ | |||
case 0: | |||
return "SmartPolicy"; | |||
case 1: | |||
return "FireNow"; | |||
case 2: | |||
return "RescheduleNowWithExistingRepeatCount"; | |||
case 3: | |||
return "RescheduleNowWithRemainingRepeatCount"; | |||
case 4: | |||
return "RescheduleNextWithRemainingCount"; | |||
case 5: | |||
return "RescheduleNextWithExistingCount"; | |||
default: | |||
throw new ArgumentOutOfRangeException(string.Format("{0} is not a supported misfire instruction for SimpleTrigger See Quartz.MisfireInstruction for more details.", misfireInstruction)); | |||
} | |||
} | |||
private string getSimpleTriggerMisfireInstructionText(int misfireInstruction) | |||
{ | |||
switch (misfireInstruction) | |||
{ | |||
case 0: | |||
return "SmartPolicy"; | |||
case 1: | |||
return "FireNow"; | |||
case 2: | |||
return "RescheduleNowWithExistingRepeatCount"; | |||
case 3: | |||
return "RescheduleNowWithRemainingRepeatCount"; | |||
case 4: | |||
return "RescheduleNextWithRemainingCount"; | |||
case 5: | |||
return "RescheduleNextWithExistingCount"; | |||
default: | |||
throw new ArgumentOutOfRangeException(string.Format("{0} is not a supported misfire instruction for SimpleTrigger See Quartz.MisfireInstruction for more details.", misfireInstruction)); | |||
} | |||
} | |||
private string getCronTriggerMisfireInstructionText(int misfireInstruction) | |||
{ | |||
switch (misfireInstruction) | |||
{ | |||
case 0: | |||
return "SmartPolicy"; | |||
case 1: | |||
return "FireOnceNow"; | |||
case 2: | |||
return "DoNothing"; | |||
default: | |||
throw new ArgumentOutOfRangeException(string.Format("{0} is not a supported misfire instruction for CronTrigger See Quartz.MisfireInstruction for more details.", misfireInstruction)); | |||
} | |||
} | |||
private string getCronTriggerMisfireInstructionText(int misfireInstruction) | |||
{ | |||
switch (misfireInstruction) | |||
{ | |||
case 0: | |||
return "SmartPolicy"; | |||
case 1: | |||
return "FireOnceNow"; | |||
case 2: | |||
return "DoNothing"; | |||
default: | |||
throw new ArgumentOutOfRangeException(string.Format("{0} is not a supported misfire instruction for CronTrigger See Quartz.MisfireInstruction for more details.", misfireInstruction)); | |||
} | |||
} | |||
private XElement getSimpleTrigger(XNamespace ns, SimpleTrigger trigger) | |||
{ | |||
XElement simpleTrigger = new XElement(ns + "simple"); | |||
addCommonTriggerData(ns, simpleTrigger, trigger); | |||
simpleTrigger.Add( | |||
new XElement(ns + "repeat-count", trigger.RepeatCount) | |||
, new XElement(ns + "repeat-interval", trigger.RepeatInterval.Milliseconds) | |||
); | |||
return simpleTrigger; | |||
} | |||
} | |||
private XElement getSimpleTrigger(XNamespace ns, SimpleTriggerImpl trigger) | |||
{ | |||
XElement simpleTrigger = new XElement(ns + "simple"); | |||
addCommonTriggerData(ns, simpleTrigger, trigger); | |||
simpleTrigger.Add( | |||
new XElement(ns + "repeat-count", trigger.RepeatCount) | |||
, new XElement(ns + "repeat-interval", trigger.RepeatInterval.Milliseconds) | |||
); | |||
return simpleTrigger; | |||
} | |||
} | |||
} |
@@ -4,17 +4,18 @@ using System.Linq; | |||
using System.Text; | |||
using System.Windows.Forms; | |||
using Quartz; | |||
using Quartz.Impl.Triggers; | |||
namespace ClickForensics.Quartz.Manager | |||
{ | |||
public class TriggerNode : TreeNode | |||
{ | |||
public TriggerNode(Trigger trigger) | |||
{ | |||
Text = trigger.Name; | |||
Trigger = trigger; | |||
} | |||
public Trigger Trigger { get; set; } | |||
} | |||
public class TriggerNode : TreeNode | |||
{ | |||
public TriggerNode(AbstractTrigger trigger) | |||
{ | |||
Text = trigger.Name; | |||
Trigger = trigger; | |||
} | |||
public AbstractTrigger Trigger { get; set; } | |||
} | |||
} |