/// <summary> /// Inserts a WebDeleteStudy work queue entry that deletes specific SOP Instances within the study. /// </summary> /// <param name="context"></param> /// <param name="location"></param> /// <param name="seriesInstanceUid"></param> /// <param name="sopInstanceUid"></param> /// <param name="reason"></param> /// <param name="externalRequest"></param> public static WorkQueue InsertDeleteInstanceRequest(IUpdateContext context, StudyStorageLocation location, string seriesInstanceUid, string sopInstanceUid, string reason, ExternalRequestQueue externalRequest = null) { var broker = context.GetBroker <IInsertWorkQueue>(); DateTime now = Platform.Time; var criteria = new InsertWorkQueueParameters { WorkQueueTypeEnum = WorkQueueTypeEnum.WebDeleteStudy, StudyStorageKey = location.Key, ServerPartitionKey = location.ServerPartitionKey, ScheduledTime = now, SeriesInstanceUid = seriesInstanceUid, SopInstanceUid = sopInstanceUid, WorkQueueData = XmlUtils.SerializeAsXmlDoc( new WebDeleteInstanceLevelQueueData { Reason = reason, Timestamp = now, UserId = ServerHelper.CurrentUserId, UserName = ServerHelper.CurrentUserName }), }; if (externalRequest != null) { criteria.ExternalRequestQueueKey = externalRequest.Key; } return(broker.FindOne(criteria)); }
/// <summary> /// Inserts a WebDeleteStudy request for a specific Study /// </summary> /// <param name="updateContext">The database context to insert under.</param> /// <param name="location">The StudyStorageLocation of the study to delete.</param> /// <param name="requestDescription">A description of the reason for the delete.</param> /// <param name="externalRequest">An optional external request that triggered this deletion</param> /// <returns>The inserted WorkQueue entry</returns> public static WorkQueue InsertDeleteStudyRequest(IUpdateContext updateContext, StudyStorageLocation location, string requestDescription, ExternalRequestQueue externalRequest = null) { var extendedData = new WebDeleteStudyLevelQueueData { Level = DeletionLevel.Study, Reason = requestDescription, UserId = ServerHelper.CurrentUserId, UserName = ServerHelper.CurrentUserName }; var insertParms = new InsertWorkQueueParameters { WorkQueueTypeEnum = WorkQueueTypeEnum.WebDeleteStudy, ServerPartitionKey = location.ServerPartitionKey, StudyStorageKey = location.Key, ScheduledTime = Platform.Time, WorkQueueData = XmlUtils.SerializeAsXmlDoc(extendedData) }; if (externalRequest != null) { insertParms.ExternalRequestQueueKey = externalRequest.Key; } var insertWorkQueue = updateContext.GetBroker <IInsertWorkQueue>(); return(insertWorkQueue.FindOne(insertParms)); }
protected override void OnExecute(CommandProcessor theProcessor, IUpdateContext updateContext) { var insert = updateContext.GetBroker <IInsertWorkQueue>(); var parms = new InsertWorkQueueParameters { WorkQueueTypeEnum = WorkQueueTypeEnum.StudyProcess, StudyStorageKey = _storageLocation.GetKey(), ServerPartitionKey = _storageLocation.ServerPartitionKey, SeriesInstanceUid = _message.DataSet[DicomTags.SeriesInstanceUid].GetString(0, String.Empty), SopInstanceUid = _message.DataSet[DicomTags.SopInstanceUid].GetString(0, String.Empty), ScheduledTime = Platform.Time, WorkQueueGroupID = _uidGroupId }; if (_duplicate) { parms.Duplicate = _duplicate; parms.Extension = _extension; parms.UidGroupID = _uidGroupId; } _insertedWorkQueue = insert.FindOne(parms); if (_insertedWorkQueue == null) { throw new ApplicationException("UpdateWorkQueueCommand failed"); } }
/// <summary> /// Do the insertion of the AutoRoute. /// </summary> protected override void OnExecute(CommandProcessor theProcessor, IUpdateContext updateContext) { DeviceSelectCriteria deviceSelectCriteria = new DeviceSelectCriteria(); deviceSelectCriteria.AeTitle.EqualTo(_deviceAe); deviceSelectCriteria.ServerPartitionKey.EqualTo(_context.ServerPartitionKey); IDeviceEntityBroker selectDevice = updateContext.GetBroker <IDeviceEntityBroker>(); Device dev = selectDevice.FindOne(deviceSelectCriteria); if (dev == null) { Platform.Log(LogLevel.Warn, "Device '{0}' on partition {1} not in database for autoroute request! Ignoring request.", _deviceAe, _context.ServerPartition.AeTitle); ServerPlatform.Alert( AlertCategory.Application, AlertLevel.Warning, SR.AlertComponentAutorouteRule, AlertTypeCodes.UnableToProcess, null, TimeSpan.FromMinutes(5), SR.AlertAutoRouteUnknownDestination, _deviceAe, _context.ServerPartition.AeTitle); return; } if (!dev.AllowAutoRoute) { Platform.Log(LogLevel.Warn, "Auto-route attempted to device {0} on partition {1} with autoroute support disabled. Ignoring request.", dev.AeTitle, _context.ServerPartition.AeTitle); ServerPlatform.Alert(AlertCategory.Application, AlertLevel.Warning, SR.AlertComponentAutorouteRule, AlertTypeCodes.UnableToProcess, null, TimeSpan.FromMinutes(5), SR.AlertAutoRouteDestinationAEDisabled, dev.AeTitle, _context.ServerPartition.AeTitle); return; } InsertWorkQueueParameters parms = new InsertWorkQueueParameters { WorkQueueTypeEnum = WorkQueueTypeEnum.AutoRoute, ScheduledTime = _scheduledTime.HasValue ? _scheduledTime.Value : Platform.Time.AddSeconds(10), StudyStorageKey = _context.StudyLocationKey, ServerPartitionKey = _context.ServerPartitionKey, DeviceKey = dev.GetKey(), SeriesInstanceUid = _context.Message.DataSet[DicomTags.SeriesInstanceUid].GetString(0, string.Empty), SopInstanceUid = _context.Message.DataSet[DicomTags.SopInstanceUid].GetString(0, string.Empty) }; IInsertWorkQueue broker = updateContext.GetBroker <IInsertWorkQueue>(); if (broker.FindOne(parms) == null) { throw new ApplicationException("InsertAutoRouteCommand failed"); } }
/// <summary> /// Delete a Study. /// </summary> public void DeleteStudy(ServerEntityKey studyKey, string reason) { StudySummary study = StudySummaryAssembler.CreateStudySummary(HttpContextData.Current.ReadContext, Study.Load(HttpContextData.Current.ReadContext, studyKey)); if (study.IsReconcileRequired) { throw new ApplicationException( String.Format("Deleting the study is not allowed at this time : there are items to be reconciled.")); // NOTE: another check will occur when the delete is actually processed } using (IUpdateContext ctx = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush)) { LockStudyParameters lockParms = new LockStudyParameters { QueueStudyStateEnum = QueueStudyStateEnum.WebDeleteScheduled, StudyStorageKey = study.TheStudyStorage.Key }; ILockStudy broker = ctx.GetBroker <ILockStudy>(); broker.Execute(lockParms); if (!lockParms.Successful) { throw new ApplicationException(String.Format("Unable to lock the study : {0}", lockParms.FailureReason)); } InsertWorkQueueParameters insertParms = new InsertWorkQueueParameters { WorkQueueTypeEnum = WorkQueueTypeEnum.WebDeleteStudy, ServerPartitionKey = study.ThePartition.Key, StudyStorageKey = study.TheStudyStorage.Key, ScheduledTime = Platform.Time }; WebDeleteStudyLevelQueueData extendedData = new WebDeleteStudyLevelQueueData { Level = DeletionLevel.Study, Reason = reason, UserId = ServerHelper.CurrentUserId, UserName = ServerHelper.CurrentUserName }; insertParms.WorkQueueData = XmlUtils.SerializeAsXmlDoc(extendedData); IInsertWorkQueue insertWorkQueue = ctx.GetBroker <IInsertWorkQueue>(); if (insertWorkQueue.FindOne(insertParms) == null) { throw new ApplicationException("DeleteStudy failed"); } ctx.Commit(); } }
protected override void OnExecute(CommandProcessor theProcessor, IUpdateContext updateContext) { var insert = updateContext.GetBroker <IInsertWorkQueue>(); var parms = new InsertWorkQueueParameters { WorkQueueTypeEnum = WorkQueueTypeEnum.StudyProcess, StudyStorageKey = _storageLocation.GetKey(), ServerPartitionKey = _storageLocation.ServerPartitionKey, SeriesInstanceUid = _message.DataSet[DicomTags.SeriesInstanceUid].GetString(0, String.Empty), SopInstanceUid = _message.DataSet[DicomTags.SopInstanceUid].GetString(0, String.Empty), ScheduledTime = Platform.Time, }; if (_priority != null) { parms.WorkQueuePriorityEnum = _priority; } if (_data != null) { parms.WorkQueueData = ImageServerSerializer.SerializeWorkQueueDataToXmlDocument(_data); } if (_request != null) { parms.ExternalRequestQueueKey = _request.Key; } if (_uidData != null) { parms.WorkQueueUidData = _uidData; parms.Extension = _uidData.Extension; parms.UidGroupID = _uidData.GroupId; parms.WorkQueueGroupID = _uidData.GroupId; } if (_duplicate) { parms.Duplicate = _duplicate; } _insertedWorkQueue = insert.FindOne(parms); if (_insertedWorkQueue == null) { throw new ApplicationException("UpdateWorkQueueCommand failed"); } }
/// <summary> /// Inserts a <see cref="WorkQueue"/> request to reprocess the study /// </summary> /// <param name="ctx"></param> /// <param name="reason"></param> /// <param name="location"></param> /// <param name="additionalPaths"></param> /// <param name="scheduleTime"></param> /// <returns></returns> /// <exception cref="InvalidStudyStateOperationException">Study is in a state that reprocessing is not allowed</exception> /// public WorkQueue ReprocessStudy(IUpdateContext ctx, String reason, StudyStorageLocation location, List <FilesystemDynamicPath> additionalPaths, DateTime scheduleTime) { Platform.CheckForNullReference(location, "location"); if (location.StudyStatusEnum.Equals(StudyStatusEnum.OnlineLossy)) { if (location.IsLatestArchiveLossless) { string message = String.Format("Study has been archived as lossless and is currently lossy. It must be restored first"); throw new InvalidStudyStateOperationException(message); } } Study study = location.LoadStudy(ctx); // Unlock first. ILockStudy lockStudy = ctx.GetBroker <ILockStudy>(); LockStudyParameters lockParms = new LockStudyParameters(); lockParms.StudyStorageKey = location.Key; lockParms.QueueStudyStateEnum = QueueStudyStateEnum.Idle; if (!lockStudy.Execute(lockParms) || !lockParms.Successful) { // Note: according to the stored proc, setting study state to Idle always succeeds so // this will never happen return(null); } // Now relock into ReprocessScheduled state. If another process locks the study before this occurs, // lockParms.QueueStudyStateEnum = QueueStudyStateEnum.ReprocessScheduled; if (!lockStudy.Execute(lockParms) || !lockParms.Successful) { throw new InvalidStudyStateOperationException(lockParms.FailureReason); } InsertWorkQueueParameters columns = new InsertWorkQueueParameters(); columns.ScheduledTime = scheduleTime; columns.ServerPartitionKey = location.ServerPartitionKey; columns.StudyStorageKey = location.Key; columns.WorkQueueTypeEnum = WorkQueueTypeEnum.ReprocessStudy; ReprocessStudyQueueData queueData = new ReprocessStudyQueueData(); queueData.State = new ReprocessStudyState(); queueData.State.ExecuteAtLeastOnce = false; queueData.ChangeLog = new ReprocessStudyChangeLog(); queueData.ChangeLog.Reason = reason; queueData.ChangeLog.TimeStamp = Platform.Time; queueData.ChangeLog.User = (Thread.CurrentPrincipal is CustomPrincipal) ? (Thread.CurrentPrincipal as CustomPrincipal).Identity.Name : String.Empty; if (additionalPaths != null) { queueData.AdditionalFiles = additionalPaths.ConvertAll <string>(path => path.ToString()); } columns.WorkQueueData = XmlUtils.SerializeAsXmlDoc(queueData); IInsertWorkQueue insertBroker = ctx.GetBroker <IInsertWorkQueue>(); WorkQueue reprocessEntry = insertBroker.FindOne(columns); if (reprocessEntry != null) { if (study != null) { Platform.Log(LogLevel.Info, "Study Reprocess Scheduled for Study {0}, A#: {1}, Patient: {2}, ID={3}", study.StudyInstanceUid, study.AccessionNumber, study.PatientsName, study.PatientId); } else { Platform.Log(LogLevel.Info, "Study Reprocess Scheduled for Study {0}.", location.StudyInstanceUid); } } return(reprocessEntry); }
private void ReinventoryFilesystem(Filesystem filesystem) { ServerPartition partition; DirectoryInfo filesystemDir = new DirectoryInfo(filesystem.FilesystemPath); foreach (DirectoryInfo partitionDir in filesystemDir.GetDirectories()) { if (GetServerPartition(partitionDir.Name, out partition) == false) { continue; } foreach (DirectoryInfo dateDir in partitionDir.GetDirectories()) { if (dateDir.FullName.EndsWith("Deleted", StringComparison.InvariantCultureIgnoreCase) || dateDir.FullName.EndsWith(ServerPlatform.ReconcileStorageFolder, StringComparison.InvariantCultureIgnoreCase)) { continue; } List <FileInfo> fileList; foreach (DirectoryInfo studyDir in dateDir.GetDirectories()) { if (studyDir.FullName.EndsWith("Deleted", StringComparison.InvariantCultureIgnoreCase)) { continue; } // Check for Cancel message if (CancelPending) { return; } String studyInstanceUid = studyDir.Name; StudyStorageLocation location; if (GetStudyStorageLocation(partition.Key, studyInstanceUid, out location)) { #region Study record exists in db int integrityQueueCount; int workQueueCount; Study theStudy = GetStudyAndQueues(location, out integrityQueueCount, out workQueueCount); if (theStudy != null) { continue; } if (integrityQueueCount != 0 && workQueueCount != 0) { continue; } fileList = LoadSopFiles(studyDir, false); if (fileList.Count == 0) { Platform.Log(LogLevel.Warn, "Found empty study folder with StorageLocation, deleteing StorageLocation: {0}\\{1}", dateDir.Name, studyDir.Name); studyDir.Delete(true); RemoveStudyStorage(location); continue; } // WriteLock the new study storage for study processing if (!location.QueueStudyStateEnum.Equals(QueueStudyStateEnum.ProcessingScheduled)) { string failureReason; if (!ServerHelper.LockStudy(location.Key, QueueStudyStateEnum.ProcessingScheduled, out failureReason)) { Platform.Log(LogLevel.Error, "Unable to lock study {0} for Study Processing", location.StudyInstanceUid); } } #endregion } else { #region Directory not in DB, fileList = LoadSopFiles(studyDir, true); if (fileList.Count == 0) { Platform.Log(LogLevel.Warn, "Found empty study folder: {0}\\{1}", dateDir.Name, studyDir.Name); continue; } DicomFile file = LoadFileFromList(fileList); if (file == null) { Platform.Log(LogLevel.Warn, "Found directory with no readable files: {0}\\{1}", dateDir.Name, studyDir.Name); continue; } // Do a second check, using the study instance uid from a file in the directory. // had an issue with trailing periods on uids causing us to not find the // study storage, and insert a new record into the database. studyInstanceUid = file.DataSet[DicomTags.StudyInstanceUid].ToString(); if (GetStudyStorageLocation(partition.Key, studyInstanceUid, out location)) { continue; } StudyStorage storage; if (GetStudyStorage(partition, studyInstanceUid, out storage)) { Platform.Log(LogLevel.Warn, "Study {0} on filesystem partition {1} is offline {2}", studyInstanceUid, partition.Description, studyDir.ToString()); continue; } Platform.Log(LogLevel.Info, "Reinventory inserting study storage location for {0} on partition {1}", studyInstanceUid, partition.Description); // Insert StudyStorage using (IUpdateContext update = _store.OpenUpdateContext(UpdateContextSyncMode.Flush)) { IInsertStudyStorage studyInsert = update.GetBroker <IInsertStudyStorage>(); InsertStudyStorageParameters insertParms = new InsertStudyStorageParameters { ServerPartitionKey = partition.GetKey(), StudyInstanceUid = studyInstanceUid, Folder = dateDir.Name, FilesystemKey = filesystem.GetKey(), QueueStudyStateEnum = QueueStudyStateEnum.Idle }; if (file.TransferSyntax.LosslessCompressed) { insertParms.TransferSyntaxUid = file.TransferSyntax.UidString; insertParms.StudyStatusEnum = StudyStatusEnum.OnlineLossless; } else if (file.TransferSyntax.LossyCompressed) { insertParms.TransferSyntaxUid = file.TransferSyntax.UidString; insertParms.StudyStatusEnum = StudyStatusEnum.OnlineLossy; } else { insertParms.TransferSyntaxUid = file.TransferSyntax.UidString; insertParms.StudyStatusEnum = StudyStatusEnum.Online; } location = studyInsert.FindOne(insertParms); // WriteLock the new study storage for study processing ILockStudy lockStudy = update.GetBroker <ILockStudy>(); LockStudyParameters lockParms = new LockStudyParameters { StudyStorageKey = location.Key, QueueStudyStateEnum = QueueStudyStateEnum.ProcessingScheduled }; if (!lockStudy.Execute(lockParms) || !lockParms.Successful) { Platform.Log(LogLevel.Error, "Unable to lock study {0} for Study Processing", location.StudyInstanceUid); } update.Commit(); } #endregion } string studyXml = location.GetStudyXmlPath(); if (File.Exists(studyXml)) { FileUtils.Delete(studyXml); } string studyGZipXml = location.GetCompressedStudyXmlPath(); if (File.Exists(studyGZipXml)) { FileUtils.Delete(studyGZipXml); } foreach (FileInfo sopFile in fileList) { String sopInstanceUid = sopFile.Name.Replace(sopFile.Extension, string.Empty); using (ServerExecutionContext context = new ServerExecutionContext()) { // Just use a read context here, in hopes of improving // performance. Every other place in the code should use // Update contexts when doing transactions. IInsertWorkQueue workQueueInsert = context.ReadContext.GetBroker <IInsertWorkQueue>(); InsertWorkQueueParameters queueInsertParms = new InsertWorkQueueParameters { WorkQueueTypeEnum = WorkQueueTypeEnum.StudyProcess, StudyStorageKey = location.GetKey(), ServerPartitionKey = partition.GetKey(), SeriesInstanceUid = sopFile.Directory.Name, SopInstanceUid = sopInstanceUid, ScheduledTime = Platform.Time }; if (workQueueInsert.FindOne(queueInsertParms) == null) { Platform.Log(LogLevel.Error, "Failure attempting to insert SOP Instance into WorkQueue during Reinventory."); } } } } // Cleanup the date directory, if its empty. DirectoryUtility.DeleteIfEmpty(dateDir.FullName); } } }
/// <summary> /// Do the insertion of the AutoRoute. /// </summary> protected override void OnExecute(CommandProcessor theProcessor, IUpdateContext updateContext) { var deviceSelectCriteria = new DeviceSelectCriteria(); deviceSelectCriteria.AeTitle.EqualTo(_deviceAe); deviceSelectCriteria.ServerPartitionKey.EqualTo(_context.ServerPartitionKey); var selectDevice = updateContext.GetBroker <IDeviceEntityBroker>(); var dev = selectDevice.FindOne(deviceSelectCriteria); if (dev == null) { Platform.Log(LogLevel.Warn, "Device '{0}' on partition {1} not in database for autoroute request! Ignoring request.", _deviceAe, _context.ServerPartition.AeTitle); ServerPlatform.Alert( AlertCategory.Application, AlertLevel.Warning, SR.AlertComponentAutorouteRule, AlertTypeCodes.UnableToProcess, null, TimeSpan.FromMinutes(5), SR.AlertAutoRouteUnknownDestination, _deviceAe, _context.ServerPartition.AeTitle); return; } if (!dev.AllowAutoRoute) { Platform.Log(LogLevel.Warn, "Study Auto-route attempted to device {0} on partition {1} with autoroute support disabled. Ignoring request.", dev.AeTitle, _context.ServerPartition.AeTitle); ServerPlatform.Alert(AlertCategory.Application, AlertLevel.Warning, SR.AlertComponentAutorouteRule, AlertTypeCodes.UnableToProcess, null, TimeSpan.FromMinutes(5), SR.AlertAutoRouteDestinationAEDisabled, dev.AeTitle, _context.ServerPartition.AeTitle); return; } if (_qcStatus != null) { var studyBroker = updateContext.GetBroker <IStudyEntityBroker>(); var studySelect = new StudySelectCriteria(); studySelect.StudyStorageKey.EqualTo(_context.StudyLocationKey); studySelect.ServerPartitionKey.EqualTo(_context.ServerPartitionKey); var study = studyBroker.FindOne(studySelect); if (!study.QCStatusEnum.Equals(_qcStatus)) { Platform.Log(LogLevel.Debug, "Ignoring Auto-route where the QCStatusEnum status must be {0}, but database has {1} for study {2}", _qcStatus.Description, study.QCStatusEnum.Description, study.StudyInstanceUid); return; } } var parms = new InsertWorkQueueParameters { WorkQueueTypeEnum = WorkQueueTypeEnum.StudyAutoRoute, ScheduledTime = _scheduledTime.HasValue ? _scheduledTime.Value : Platform.Time.AddSeconds(30), StudyStorageKey = _context.StudyLocationKey, ServerPartitionKey = _context.ServerPartitionKey, DeviceKey = dev.GetKey() }; var broker = updateContext.GetBroker <IInsertWorkQueue>(); if (broker.FindOne(parms) == null) { throw new ApplicationException("InsertWorkQueue for Study Auto-Route failed"); } }