/// <summary> /// Builds a domain consisting of the IDs of every job in the database that /// has not already been closed. /// </summary> /// <param name="wmxDb">A reference to the active Workflow Manager database</param> /// <returns>A coded value domain as an IGPDomain</returns> public static IGPDomain BuildNonClosedJobIdDomain(IJTXDatabase3 wmxDb) { IGPCodedValueDomain domain = new GPCodedValueDomainClass(); // Set up a query filter to return only those jobs that are not closed IQueryFilter queryFilter = new QueryFilterClass(); queryFilter.WhereClause = ESRI.ArcGIS.JTX.Utilities.Constants.FIELD_STAGE + " <> '" + ((int)jtxJobStage.jtxJobStageClosed).ToString() + "'"; IJTXJobSet nonClosedJobs = wmxDb.JobManager.GetJobsByQuery(queryFilter); // Iterate through this job list, sorting the IDs SortedList <int, string> sortedJobIds = new SortedList <int, string>(); for (int i = 0; i < nonClosedJobs.Count; i++) { IJTXJob3 job = nonClosedJobs.get_Item(i) as IJTXJob3; sortedJobIds[job.ID] = null; } // Build a GP domain from the sorted job IDs. foreach (int id in sortedJobIds.Keys) { IGPValue tempGpVal = new GPLongClass(); tempGpVal.SetAsText(id.ToString()); domain.AddCode(tempGpVal, id.ToString()); } return(domain as IGPDomain); }
/// <summary> /// Find those priority levels in the database that are not being used by any /// job or job type. /// </summary> /// <returns>The total number of orphaned items found</returns> private int UpdateOrphanedPriorityTypes() { Dictionary <int, string> usedTypes = new Dictionary <int, string>(); IJTXDatabase3 wmxDb = this.WmxDatabase; // Check all the jobs for priorities currently in use IJTXJobSet allJobs = wmxDb.JobManager.GetAllJobs(); for (int i = 0; i < allJobs.Count; i++) { IJTXJob3 job = allJobs.get_Item(i) as IJTXJob3; if (!usedTypes.ContainsKey(job.Priority.Value)) { usedTypes[job.Priority.Value] = job.Priority.Name; } } // Check the template job types for default priorities in use IJTXJobTypeSet allJobTypes = wmxDb.ConfigurationManager.JobTypes; for (int i = 0; i < allJobTypes.Count; i++) { // TODO: Skip unused job types IJTXJobType3 jobType = allJobTypes.get_Item(i) as IJTXJobType3; if (!usedTypes.ContainsKey(jobType.DefaultPriority.Value)) { usedTypes[jobType.DefaultPriority.Value] = jobType.DefaultPriority.Name; } } // Loop over all of the priorities. For anything whose name is not contained // in the "used" list, add it to the "unused" list. If all of the items are // used, don't bother trying to add to the unused list. IJTXPrioritySet allTypes = wmxDb.ConfigurationManager.Priorities; if (usedTypes.Count != allTypes.Count) { for (int i = 0; i < allTypes.Count; i++) { IJTXPriority priority = allTypes.get_Item(i) as IJTXPriority; if (!usedTypes.ContainsKey(priority.Value)) { m_unusedPriorities[priority.Value] = priority.Name; } } } return(m_unusedPriorities.Count); }
//////////////////////////////////////////////////////////////////////// // METHOD: CreateJobs private int CreateJobs(IJTXJob2 pParentJob) { try { System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.WaitCursor; bool bAutoCommit = ConfigurationCache.AutoCommitWorkflow; m_ipDatabase.LogMessage(5, 2000, "CreateJobs"); // Set the job template values IJTXJobManager2 pJobMan = m_ipDatabase.JobManager as IJTXJobManager2; IJTXJobDescription pJobDescription = new JTXJobDescriptionClass(); pJobDescription.Description = pParentJob.Description; pJobDescription.Priority = pParentJob.Priority; pJobDescription.ParentJobId = pParentJob.ID; pJobDescription.StartDate = pParentJob.StartDate; if (m_dueDate != Constants.NullDate) pJobDescription.DueDate = m_dueDate; else if (m_duration > 0) pJobDescription.DueDate = System.DateTime.Now.AddDays(m_duration); else pJobDescription.DueDate = pParentJob.DueDate; if (!String.IsNullOrEmpty(m_paramAssignToGroup)) { pJobDescription.AssignedType = jtxAssignmentType.jtxAssignmentTypeGroup; pJobDescription.AssignedTo = m_paramAssignToGroup; } else if (!String.IsNullOrEmpty(m_paramAssignToUser)) { pJobDescription.AssignedType = jtxAssignmentType.jtxAssignmentTypeUser; pJobDescription.AssignedTo = m_paramAssignToUser; } else { pJobDescription.AssignedType = jtxAssignmentType.jtxAssignmentTypeUnassigned; } pJobDescription.OwnedBy = ConfigurationCache.GetCurrentJTXUser().UserName; if (pParentJob.ActiveDatabase != null) pJobDescription.DataWorkspaceID = pParentJob.ActiveDatabase.DatabaseID; // Set the parent version. This only makes sense if the active workspace has been set if (pJobDescription.DataWorkspaceID != null) { if (m_paramCreateVersionType == CreateVersionType.None || m_paramCreateVersionType == CreateVersionType.UseParentJobsVersion) pJobDescription.ParentVersionName = pParentJob.VersionName; // This has to be set here because setting the job workspace resets the value else if (m_paramCreateVersionType == CreateVersionType.UseJobTypeDefaultSettings) { IJTXJobType pJobType = m_ipDatabase.ConfigurationManager.GetJobType(m_paramJobTypeName); if (pJobType != null) pJobDescription.ParentVersionName = pJobType.DefaultParentVersionName; } else if (m_paramCreateVersionType == CreateVersionType.UseParentJobsDefaultVersion) pJobDescription.ParentVersionName = pParentJob.JobType.DefaultParentVersionName; else if (m_paramCreateVersionType == CreateVersionType.UseParentJobsParentVersion) pJobDescription.ParentVersionName = pParentJob.ParentVersion; } // Determine the number of jobs to make m_ipDatabase.LogMessage(5, 2000, "Before Determining Number of Jobs"); IArray aoiList = null; int numJobs; if (!GetNumberOfJobs(pParentJob, ref aoiList, out numJobs)) return 1; if (numJobs <= 0) { MessageBox.Show(Properties.Resources.ZeroJobCount); return 0; } pJobDescription.AOIList = aoiList; m_ipDatabase.LogMessage(5, 2000, "After Determining Number of Jobs"); // Create the job objects m_ipDatabase.LogMessage(5, 2000, "Before CreateJobs"); pJobDescription.JobTypeName = m_paramJobTypeName; IJTXExecuteInfo pExecInfo; m_ipJobs = pJobMan.CreateJobsFromDescription(pJobDescription, numJobs, true, out pExecInfo); m_ipDatabase.LogMessage(5, 2000, "After CreateJobs"); // Populate the job data for (int i = 0; i < m_ipJobs.Count; ++i) { IJTXJob pJob = m_ipJobs.get_Item(i); SetJobProperties(pJobMan, pJob, pParentJob); } return 1; } catch (COMException ex) { if (ex.ErrorCode == (int)fdoError.FDO_E_SE_INVALID_COLUMN_VALUE) { MessageBox.Show(Properties.Resources.InvalidColumn, Properties.Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } else { MessageBox.Show(ex.Message); } return 0; } catch (Exception ex2) { MessageBox.Show(ex2.Message, Properties.Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return 0; } finally { System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.Default; } }
/// <summary> /// Find those users in the database who are not being referenced in any way /// </summary> /// <returns>The total number of orphaned items found</returns> private int UpdateOrphanedUsers() { SortedList <string, string> unusedItems = new SortedList <string, string>(); IJTXDatabase3 wmxDb = this.WmxDatabase; IJTXConfiguration3 configMgr = wmxDb.ConfigurationManager as IJTXConfiguration3; IJTXJobManager jobMgr = wmxDb.JobManager; IJTXUserSet allUsers = configMgr.Users; Dictionary <string, string> usedItems = new Dictionary <string, string>(); // Get all of the users who are members of a group IJTXUserGroupSet allGroups = configMgr.UserGroups; for (int i = 0; i < allGroups.Count; i++) { IJTXUserGroup2 group = allGroups.get_Item(i) as IJTXUserGroup2; for (int j = 0; j < group.Users.Count; j++) { IJTXUser3 user = group.Users.get_Item(j) as IJTXUser3; usedItems[user.UserName] = user.FullName; } } // If necessary, add in the users who have jobs assigned to them if (usedItems.Count < allUsers.Count) { IJTXJobSet allJobs = jobMgr.GetAllJobs(); for (int i = 0; i < allJobs.Count; i++) { IJTXJob3 job = allJobs.get_Item(i) as IJTXJob3; if (job.AssignedType == jtxAssignmentType.jtxAssignmentTypeUser) { IJTXUser3 user = configMgr.GetUser(job.AssignedTo) as IJTXUser3; // It's possible for a user to have a job assigned, but have // already been removed from the DB. Throw an exception in // this case, as the DB needs to be cleaned up. if (user == null) { throw new WmauException(WmauErrorCodes.C_USER_NOT_FOUND_ERROR); } usedItems[user.UserName] = user.FullName; } } } // If necessary, add in the users who have a job type's default assignment // set to them if (usedItems.Count < allUsers.Count) { IJTXJobTypeSet allJobTypes = configMgr.JobTypes; for (int i = 0; i < allJobTypes.Count; i++) { // TODO: Exclude orphaned job types IJTXJobType3 jobType = allJobTypes.get_Item(i) as IJTXJobType3; if (jobType.DefaultAssignedType == jtxAssignmentType.jtxAssignmentTypeUser) { IJTXUser3 user = configMgr.GetUser(jobType.DefaultAssignedTo) as IJTXUser3; // It's possible for a user to have a job assigned, but have // already been removed from the DB. Throw an exception in // this case, as the DB needs to be cleaned up. if (user == null) { throw new WmauException(WmauErrorCodes.C_USER_NOT_FOUND_ERROR); } usedItems[user.UserName] = user.FullName; } } } // If necessary, add in the users who have steps assigned to them // by default if (usedItems.Count < allUsers.Count) { IJTXWorkflowSet allWorkflows = configMgr.Workflows; for (int i = 0; i < allWorkflows.Count; i++) { // Skip over unused workflows IJTXWorkflow workflow = allWorkflows.get_Item(i); if (m_unusedWorkflows.Keys.Contains(workflow.ID)) { continue; } // Examine the other items IJTXWorkflowConfiguration workflowCfg = allWorkflows.get_Item(i) as IJTXWorkflowConfiguration; int[] workflowStepIds = workflowCfg.GetAllSteps(); foreach (int j in workflowStepIds) { IJTXStep3 step = workflowCfg.GetStep(j) as IJTXStep3; if (step.AssignedType == jtxAssignmentType.jtxAssignmentTypeUser) { IJTXUser3 user = configMgr.GetUser(step.AssignedTo) as IJTXUser3; // It's possible for a user to have a job assigned, but have // already been removed from the DB. Throw an exception in // this case, as the DB needs to be cleaned up. if (user == null) { throw new WmauException(WmauErrorCodes.C_USER_NOT_FOUND_ERROR); } usedItems[user.UserName] = user.FullName; } } } } // Loop over all the users in the DB, looking for anything // that we didn't identify as "in use" for (int i = 0; i < allUsers.Count; i++) { IJTXUser3 item = allUsers.get_Item(i) as IJTXUser3; if (!usedItems.ContainsKey(item.UserName)) { m_unusedUsers[item.UserName] = item.FullName; } } return(m_unusedUsers.Count); }
/// <summary> /// Find those status types in the database that are not being used by any step. /// </summary> /// <returns>The total number of orphaned items found</returns> private int UpdateOrphanedStatusTypes() { Dictionary <int, int> usedStatusTypes = new Dictionary <int, int>(); IJTXDatabase3 wmxDb = this.WmxDatabase; string[] coreStatusNames = { C_STATUS_CLOSED, C_STATUS_CREATED, C_STATUS_DONE_WORKING, C_STATUS_READY_TO_WORK, C_STATUS_WORKING }; IJTXConfiguration3 configMgr = wmxDb.ConfigurationManager as IJTXConfiguration3; // Iterate through each job currently in the system, adding the status types used // by these jobs IJTXJobSet jobs = wmxDb.JobManager.GetAllJobs(); for (int i = 0; i < jobs.Count; i++) { IJTXJob3 job = jobs.get_Item(i) as IJTXJob3; if (job.Status != null) { usedStatusTypes[job.Status.ID] = job.Status.ID; } } // Iterate through each workflow, building up the list of used status types // based on the statuses that are assigned by each step IJTXWorkflowSet workflows = configMgr.Workflows; for (int i = 0; i < workflows.Count; i++) { // Skip over those workflows that aren't in use IJTXWorkflow workflow = workflows.get_Item(i); if (m_unusedWorkflows.Keys.Contains(workflow.ID)) { continue; } // Examine the remaining workflows IJTXWorkflowConfiguration workflowCfg = workflows.get_Item(i) as IJTXWorkflowConfiguration; int[] stepIds = workflowCfg.GetAllSteps(); foreach (int stepId in stepIds) { IJTXStep3 step = workflowCfg.GetStep(stepId) as IJTXStep3; usedStatusTypes[step.StatusID] = step.StatusID; } } // Add the status types used by Workflow Manager itself foreach (string s in coreStatusNames) { IJTXStatus2 status = configMgr.GetStatus(s) as IJTXStatus2; // Avoid problems if someone deleted one of these mandatory types from the database if (status != null) { int id = status.ID; usedStatusTypes[id] = id; } } // Get the complete list of status types in the database IJTXStatusSet allStatusTypes = configMgr.Statuses; // Loop over all of the status types. For anything whose ID is not contained // in the "used" list, add it to the "unused" list. If all of the items are // used, don't bother trying to add to the unused list. if (usedStatusTypes.Count != allStatusTypes.Count) { for (int i = 0; i < allStatusTypes.Count; i++) { IJTXStatus2 statusType = allStatusTypes.get_Item(i) as IJTXStatus2; if (!usedStatusTypes.ContainsKey(statusType.ID)) { m_unusedStatusTypes[statusType.ID] = statusType.Name; } } } return(m_unusedStatusTypes.Count); }
/// <summary> /// Helper function that runs all of those checks that operate on each job; intended /// to make the checks slightly more efficient by running through them all at once /// rather than looping through all of the elements multiple times /// </summary> /// <param name="msgs">Add any GP messages to this object</param> /// <param name="errorCount">Counter used to track the number of problems found</param> /// <param name="logFileWriter">Object used to write error descriptions to a text file</param> private void ExecuteJobChecks(IGPMessages msgs, ref int errorCount, StreamWriter logFileWriter) { // Only continue executing this function if needed if (!m_flagInvalidJobAssign && !m_flagIsSelfParent && !m_flagJobsWithoutTypes) { return; } IJTXConfiguration3 configMgr = this.WmxDatabase.ConfigurationManager as IJTXConfiguration3; IJTXConfigurationEdit2 configEdit = configMgr as IJTXConfigurationEdit2; IJTXJobManager jobMgr = this.WmxDatabase.JobManager; // Use a database query as an alternate way of finding certain specific // problems with jobs. Declare some of these ComReleaser objects to help // ensure that cursors, etc., are immediately released after they go out // of scope. // Check for jobs without any job types set (should be a DB error) if (m_flagJobsWithoutTypes) { using (ComReleaser cr1 = new ComReleaser(), cr2 = new ComReleaser()) { IFeatureWorkspace featureWorkspace = this.WmxDatabase.JTXWorkspace as IFeatureWorkspace; // Get the name of the correct table from the jobs workspace, so // that the table doesn't have to be owned by the connecting user. string tableName = Common.WmauHelperFunctions.GetQualifiedTableName(Constants.JTX_TABLE_JTX_JOBS_TABLE, this.WmxDatabase.JTXWorkspace); ITable jobsTable = featureWorkspace.OpenTable(tableName); cr1.ManageLifetime(jobsTable); IQueryFilter query = new QueryFilterClass(); query.WhereClause = Constants.FIELD_JOBTYPEID + " IS NULL"; ICursor searchCursor = jobsTable.Search(query, true); cr2.ManageLifetime(searchCursor); // Store the ID and name of each job matching this query int idIndex = jobsTable.FindField(Constants.FIELD_JOBID); int nameIndex = jobsTable.FindField(Constants.FIELD_JOBNAME); IRow row = null; while ((row = searchCursor.NextRow()) != null) { string idStr = row.get_Value(idIndex).ToString(); string nameStr = row.get_Value(nameIndex).ToString(); string msg = "Job " + idStr + " (" + nameStr + ") has no associated job type"; RecordMessage(msg, msgs, logFileWriter); errorCount++; } } } // Check for jobs that are their own parent job if (m_flagIsSelfParent) { using (ComReleaser cr1 = new ComReleaser(), cr2 = new ComReleaser()) { IFeatureWorkspace featureWorkspace = this.WmxDatabase.JTXWorkspace as IFeatureWorkspace; // Get the name of the correct table from the jobs workspace, so // that the table doesn't have to be owned by the connecting user. string tableName = Common.WmauHelperFunctions.GetQualifiedTableName(Constants.JTX_TABLE_JTX_JOBS_TABLE, this.WmxDatabase.JTXWorkspace); ITable jobsTable = featureWorkspace.OpenTable(tableName); cr1.ManageLifetime(jobsTable); const string C_FIELD_PARENT_JOB = "PARENT_JOB"; IQueryFilter query = new QueryFilterClass(); query.WhereClause = Constants.FIELD_JOBID + " = " + C_FIELD_PARENT_JOB; ICursor searchCursor = jobsTable.Search(query, true); cr2.ManageLifetime(searchCursor); // Store the ID and name of each job matching this query int idIndex = jobsTable.FindField(Constants.FIELD_JOBID); int nameIndex = jobsTable.FindField(Constants.FIELD_JOBNAME); IRow row = null; while ((row = searchCursor.NextRow()) != null) { string idStr = row.get_Value(idIndex).ToString(); string nameStr = row.get_Value(nameIndex).ToString(); string msg = "Job " + idStr + " (" + nameStr + ") is its own parent"; RecordMessage(msg, msgs, logFileWriter); errorCount++; } } } // See if there are any checks selected for which we should iterate through // all of the jobs using the WMX interfaces if (m_flagInvalidJobAssign) { // Put the items into a sorted list in order to make the output easier to // read/follow IJTXJobSet allJobs = jobMgr.GetAllJobs(); SortedList <int, IJTXJob3> allJobsSorted = new SortedList <int, IJTXJob3>(); for (int i = 0; i < allJobs.Count; i++) { allJobsSorted[allJobs.get_Item(i).ID] = allJobs.get_Item(i) as IJTXJob3; } // Iterate over all of the jobs foreach (IJTXJob3 job in allJobsSorted.Values) { string assignedTo = job.AssignedTo; // Check for any existing jobs with an invalid job assignment. NOTE: only // want to flag jobs that are not closed if (m_flagInvalidJobAssign && job.Stage != jtxJobStage.jtxJobStageClosed) { if (job.AssignedType == jtxAssignmentType.jtxAssignmentTypeUser && configMgr.GetUser(assignedTo) == null) { string message = "Job '" + job.ID.ToString() + "' assigned to unknown user '" + assignedTo + "'"; RecordMessage(message, msgs, logFileWriter); errorCount++; } else if (job.AssignedType == jtxAssignmentType.jtxAssignmentTypeGroup && configMgr.GetUserGroup(assignedTo) == null) { string message = "Job '" + job.ID.ToString() + "' assigned to unknown group '" + assignedTo + "'"; RecordMessage(message, msgs, logFileWriter); errorCount++; } } } } }
//////////////////////////////////////////////////////////////////////// // METHOD: CreateJobs private int CreateJobs(IJTXJob2 pParentJob) { try { System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.WaitCursor; bool bAutoCommit = ConfigurationCache.AutoCommitWorkflow; m_ipDatabase.LogMessage(5, 2000, "CreateJobs"); // Set the job template values IJTXJobManager2 pJobMan = m_ipDatabase.JobManager as IJTXJobManager2; IJTXJobDescription pJobDescription = new JTXJobDescriptionClass(); pJobDescription.Description = pParentJob.Description; pJobDescription.Priority = pParentJob.Priority; pJobDescription.ParentJobId = pParentJob.ID; pJobDescription.StartDate = pParentJob.StartDate; if (m_dueDate != Constants.NullDate) { pJobDescription.DueDate = m_dueDate; } else if (m_duration > 0) { pJobDescription.DueDate = System.DateTime.Now.AddDays(m_duration); } else { pJobDescription.DueDate = pParentJob.DueDate; } if (!String.IsNullOrEmpty(m_paramAssignToGroup)) { pJobDescription.AssignedType = jtxAssignmentType.jtxAssignmentTypeGroup; pJobDescription.AssignedTo = m_paramAssignToGroup; } else if (!String.IsNullOrEmpty(m_paramAssignToUser)) { pJobDescription.AssignedType = jtxAssignmentType.jtxAssignmentTypeUser; pJobDescription.AssignedTo = m_paramAssignToUser; } else { pJobDescription.AssignedType = jtxAssignmentType.jtxAssignmentTypeUnassigned; } pJobDescription.OwnedBy = ConfigurationCache.GetCurrentJTXUser().UserName; if (pParentJob.ActiveDatabase != null) { pJobDescription.DataWorkspaceID = pParentJob.ActiveDatabase.DatabaseID; } // Set the parent version. This only makes sense if the active workspace has been set if (pJobDescription.DataWorkspaceID != null) { if (m_paramCreateVersionType == CreateVersionType.None || m_paramCreateVersionType == CreateVersionType.UseParentJobsVersion) { pJobDescription.ParentVersionName = pParentJob.VersionName; // This has to be set here because setting the job workspace resets the value } else if (m_paramCreateVersionType == CreateVersionType.UseJobTypeDefaultSettings) { IJTXJobType pJobType = m_ipDatabase.ConfigurationManager.GetJobType(m_paramJobTypeName); if (pJobType != null) { pJobDescription.ParentVersionName = pJobType.DefaultParentVersionName; } } else if (m_paramCreateVersionType == CreateVersionType.UseParentJobsDefaultVersion) { pJobDescription.ParentVersionName = pParentJob.JobType.DefaultParentVersionName; } else if (m_paramCreateVersionType == CreateVersionType.UseParentJobsParentVersion) { pJobDescription.ParentVersionName = pParentJob.ParentVersion; } } // Determine the number of jobs to make m_ipDatabase.LogMessage(5, 2000, "Before Determining Number of Jobs"); IArray aoiList = null; int numJobs; if (!GetNumberOfJobs(pParentJob, ref aoiList, out numJobs)) { return(1); } if (numJobs <= 0) { MessageBox.Show(Properties.Resources.ZeroJobCount); return(0); } pJobDescription.AOIList = aoiList; m_ipDatabase.LogMessage(5, 2000, "After Determining Number of Jobs"); // Create the job objects m_ipDatabase.LogMessage(5, 2000, "Before CreateJobs"); pJobDescription.JobTypeName = m_paramJobTypeName; IJTXExecuteInfo pExecInfo; m_ipJobs = pJobMan.CreateJobsFromDescription(pJobDescription, numJobs, true, out pExecInfo); m_ipDatabase.LogMessage(5, 2000, "After CreateJobs"); // Populate the job data for (int i = 0; i < m_ipJobs.Count; ++i) { IJTXJob pJob = m_ipJobs.get_Item(i); SetJobProperties(pJobMan, pJob, pParentJob); } return(1); } catch (COMException ex) { if (ex.ErrorCode == (int)fdoError.FDO_E_SE_INVALID_COLUMN_VALUE) { MessageBox.Show(Properties.Resources.InvalidColumn, Properties.Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } else { MessageBox.Show(ex.Message); } return(0); } catch (Exception ex2) { MessageBox.Show(ex2.Message, Properties.Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return(0); } finally { System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.Default; } }