// // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. // using System; using System.Collections.Generic; using Microsoft.SqlServer.Management.Sdk.Sfc; using Microsoft.SqlServer.Management.Smo.Agent; using Microsoft.SqlTools.ServiceLayer.Management; namespace Microsoft.SqlTools.ServiceLayer.Agent { internal class JobSchedulesData { #region data members // Typed List of job schedules (unshared) private List jobSchedules = new List(); private List deletedJobSchedues = new List(); private JobData parent; private CDataContainer context; private bool isReadOnly; private bool allowEnableDisable; #endregion #region construction public JobSchedulesData(CDataContainer context, JobData parent) { if (context == null) { throw new ArgumentNullException("context"); } if (parent == null) { throw new ArgumentNullException("parent"); } this.context = context; this.parent = parent; this.isReadOnly = parent.IsReadOnly; this.allowEnableDisable = parent.AllowEnableDisable; // if we're creating a new job if (this.parent.Mode != JobData.ActionMode.Edit) { this.SetDefaults(); } else { // load the schedule data from server to local copy this.LoadData(); } } #endregion #region public methods/properties /// /// List of JobScheduleData - in memory copy /// public List Schedules { get { return this.jobSchedules; } } /// /// List of removed schedules - in memory copy /// public List RemovedSchedules { get { return this.deletedJobSchedues; } } /// /// Add a schedule to JobScheduleData list - this does not apply changes on server /// /// public void AddSchedule(JobScheduleData schedule) { if (schedule == null) { throw new ArgumentNullException("schedule"); } this.jobSchedules.Add(schedule); // check to see if it has been previously removed, if so delete it from the // removed schedules list for (int i = deletedJobSchedues.Count - 1; i >= 0; i--) { JobScheduleData removedSchedule = this.deletedJobSchedues[i] as JobScheduleData; if (removedSchedule.ID == schedule.ID) { this.deletedJobSchedues.RemoveAt(i); } } } /// /// delete a schedule from JobScheduleData list - this does not apply changes on server /// /// public void DeleteSchedule(JobScheduleData schedule) { if (schedule == null) { throw new ArgumentNullException("schedule"); } if (this.jobSchedules.Contains(schedule)) { this.jobSchedules.Remove(schedule); // if it exists on the server then mark it for deletion later. Otherwise just discard the schedule. if (schedule.Created) { this.deletedJobSchedues.Add(schedule); } } } public bool IsReadOnly { get { return isReadOnly; } } public bool AllowEnableDisable { get { return this.allowEnableDisable; } } #endregion #region data loading private void LoadData() { Job job = this.Job; // load the data if (job != null) { JobScheduleCollection schedules = job.JobSchedules; for (int i = 0; i < schedules.Count; i++) { this.jobSchedules.Add(new JobScheduleData(schedules[i], this.IsReadOnly, this.AllowEnableDisable)); } } else { SetDefaults(); } } private void SetDefaults() { this.jobSchedules.Clear(); } #endregion #region events #endregion #region private helpers private Job Job { get { // try and do the lookup at the parent level Job job = null; if (this.parent != null) { job = parent.Job; } else if (this.context != null) { STParameters parameters = new STParameters(this.context.Document); string urn = String.Empty; parameters.GetParam("urn", ref urn); job = this.context.Server.GetSmoObject(new Urn(urn)) as Job; } return job; } } #endregion #region saving /// /// Save changes to the job schedules - this applies changes to server /// /// owner job /// true if any changes were commited public bool ApplyChanges(Job job) { bool changesMade = false; if (!this.IsReadOnly) { // delete any deleted schedules; foreach (JobScheduleData schedule in this.deletedJobSchedues) { if (!this.IsSharedSchedule(job.Parent as JobServer, schedule)) { // non-shared if (schedule.Created) { schedule.SetJob(job); schedule.Delete(); changesMade = true; } } else if (null != job.JobSchedules.ItemById(schedule.ID)) { // shared // Remove the selected schedule from the job. If no other jobs use the schedule, the schedule is deleted from the database. // This is now the default behavior of RemoveSharedSchedule thus we do not need an extra parameter (false) with it. job.RemoveSharedSchedule(schedule.ID); changesMade = true; } } // clear the deleted Job ScheduleList this.deletedJobSchedues.Clear(); // update the remaining schedules foreach (JobScheduleData schedule in this.jobSchedules) { if (!this.IsSharedSchedule(job.Parent as JobServer, schedule)) { // non-shared schedule.SetJob(job); if (schedule.ApplyChanges()) { changesMade = true; } } else { // create and attach if the the schedule is not shared if (!schedule.Created) { schedule.SetJob(job); changesMade = true; } else { job.AddSharedSchedule(schedule.ID); } if (schedule.ApplyChanges()) { changesMade = true; } } } } else if (this.AllowEnableDisable) { // if the schedules are readonly give them an opportunity to update themselves foreach (JobScheduleData schedule in this.jobSchedules) { if (schedule.ApplyChanges()) { changesMade = true; } } } return changesMade; } #endregion /// /// check if given schedule data is shared schedule or not /// /// /// /// private bool IsSharedSchedule(JobServer js, JobScheduleData jobScheduleData) { if (js == null) { throw new ArgumentNullException("js"); } SqlServer.Management.Smo.Server srv = js.Parent as SqlServer.Management.Smo.Server; if ((srv == null) || (srv.Information.Version.Major < 9)) { // Shared Schedules not supported prior Yukon return false; } else { // with Yukon all schedules are now shared return true; } } } }