public override void Save() { try { if (HasFileStoreChanged) { _hasFileStoreEverChanged = true; } StudyStore.UpdateConfiguration(_configuration); // if the default deletion rule was modified, kick-off a re-apply rules work item if (HasDeletionRuleChanged) { var bridge = new ReapplyRulesBridge(); bridge.ReapplyAll(new RulesEngineOptions { ApplyDeleteActions = true }); } _fileStoreDirectory = _currentFileStoreDirectory = _configuration.FileStoreDirectory; _currentDeletionRule = _configuration.DefaultDeletionRule.Clone(); //Just update all kinds of properties. NotifyFileStoreChanged(); NotifyDeletionRuleChanged(null); NotifyServiceControlLinkPropertiesChanged(); ShowValidation(false); } catch (Exception e) { ExceptionHandler.Report(e, Host.DesktopWindow); } }
public void Initialize1() { DicomServer.Tests.DicomServerTestServiceProvider.Reset(); StudyManagement.Tests.StudyStoreTestServiceProvider.Reset(); Platform.SetExtensionFactory(new UnitTestExtensionFactory { { typeof(ServiceProviderExtensionPoint), typeof(TestSystemConfigurationServiceProvider) }, { typeof(ServiceProviderExtensionPoint), typeof(ServerDirectoryTestServiceProvider) }, { typeof(ServiceProviderExtensionPoint), typeof(DicomServer.Tests.DicomServerTestServiceProvider) }, { typeof(ServiceProviderExtensionPoint), typeof(StudyManagement.Tests.StudyStoreTestServiceProvider) } }); //Force IsSupported to be re-evaluated. StudyStore.InitializeIsSupported(); }
private void ApplyDefaultDeletionRule(RulesEngineOptions context, StudyEntry study) { if (!context.ApplyDeleteActions) { return; } // TODO (CR Jun 2012): Again, seem to use "work item" mutex for all database updates. Should just pass in a boolean. using (var dac = new DataAccessContext(DataAccessContext.WorkItemMutex)) { var broker = dac.GetStudyBroker(); var dbStudy = broker.GetStudy(study.Study.StudyInstanceUid); var storageConfiguration = StudyStore.GetConfiguration(); var defaultRule = storageConfiguration.DefaultDeletionRule; if (defaultRule.Enabled) { dbStudy.SetDeleteTime(defaultRule.TimeValue, defaultRule.TimeUnit, TimeOrigin.ReceivedDate, false); } else { dbStudy.ClearDeleteTime(); } dac.Commit(); } }
private void UpdateConfigurationsAsync(object state) { var asyncState = (AsyncState)state; //This stuff can actually add up over time because it's hitting the database so frequently. //Better to do it asynchronously. var storageConfiguration = StudyStore.GetConfiguration(); var dicomServerConfiguration = DicomServer.GetConfiguration(); if (!Equals(asyncState.CurrentDicomServerConfiguration, dicomServerConfiguration)) { asyncState.SynchronizationContext.Post(ignore => NotifyDicomServerConfigurationChanged(dicomServerConfiguration), null); } var storageConfigurationChanged = HasStorageConfigurationChanged(asyncState.CurrentStorageConfiguration, storageConfiguration); //Access all the disk usage properties here, since they can take some time. bool diskUsageChanged = HasDiskUsageChanged(asyncState.CurrentStorageConfiguration, storageConfiguration); if (storageConfigurationChanged) { asyncState.SynchronizationContext.Post(ignore => NotifyStorageConfigurationChanged(storageConfiguration), null); } else if (diskUsageChanged) { asyncState.SynchronizationContext.Post(ignore => NotifyDiskUsageChanged(storageConfiguration), null); } }
public void Initialize2() { StudyStoreTestServiceProvider.Reset(); Platform.SetExtensionFactory(new NullExtensionFactory()); //Force IsSupported to be re-evaluated. StudyStore.InitializeIsSupported(); }
public void RunApplication(string[] args) { var commandLine = new CommandLine(); try { commandLine.Parse(args); } catch (Exception e) { Platform.Log(LogLevel.Info, e); Console.WriteLine(e.Message); commandLine.PrintUsage(Console.Out); Environment.Exit(-1); } try { DicomServer.DicomServer.UpdateConfiguration(new DicomServerConfiguration { HostName = commandLine.HostName, AETitle = commandLine.AETitle, Port = commandLine.Port }); } catch (Exception e) { Console.WriteLine(e.Message); Platform.Log(LogLevel.Warn, e); Environment.Exit(-1); } try { if (!String.IsNullOrEmpty(commandLine.FileStoreDirectory)) { StudyStore.UpdateConfiguration(new StorageConfiguration { FileStoreDirectory = commandLine.FileStoreDirectory, MinimumFreeSpacePercent = commandLine.MinimumFreeSpacePercent != null ? double.Parse(commandLine.MinimumFreeSpacePercent) : StorageConfiguration.AutoMinimumFreeSpace }); } } catch (Exception e) { Console.WriteLine(e.Message); Platform.Log(LogLevel.Warn, e); Environment.Exit(-1); } }
public void Initialize1() { StudyStoreTestServiceProvider.Reset(); Platform.SetExtensionFactory(new UnitTestExtensionFactory { { typeof(ServiceProviderExtensionPoint), typeof(StudyStoreTestServiceProvider) } }); //Force IsSupported to be re-evaluated. StudyStore.InitializeIsSupported(); }
public override void Start() { _delaySetFileStoreDirectory = new DelayedEventPublisher(RealSetFileStoreDirectory); _activityMonitor = WorkItemActivityMonitor.Create(); _activityMonitor.IsConnectedChanged += ActivityMonitorOnIsConnectedChanged; _configuration = StudyStore.GetConfiguration(); _fileStoreDirectory = _currentFileStoreDirectory = _configuration.FileStoreDirectory; UpdateFileStoreDriveName(); MaximumUsedSpaceChanged(); _currentDeletionRule = _configuration.DefaultDeletionRule.Clone(); base.Start(); }
public void PublishLocal(ICollection <DicomFile> files) { if (files == null || files.Count == 0) { return; } var configuration = GetServerConfiguration(); var context = new ImportStudyContext(configuration.AETitle, StudyStore.GetConfiguration(), EventSource.CurrentUser); var utility = new ImportFilesUtility(context); try { DicomProcessingResult failureResult = null; foreach (var file in files) { var importResult = utility.Import(file, BadFileBehaviourEnum.Ignore, FileImportBehaviourEnum.Save); if (importResult.DicomStatus != DicomStatuses.Success) { Platform.Log(LogLevel.Warn, "Unable to import published file: {0}", importResult.ErrorMessage); failureResult = importResult; } } if (failureResult != null) { throw new ApplicationException(failureResult.ErrorMessage); } utility.PulseStudyWorkItems(); } catch (Exception ex) { var message = string.Format("Failed to import files"); throw new DicomFilePublishingException(message, ex); } }
// Essentially this is a copy of ClearCanvas.ImageViewer.StudyManagement.Core.DicomFilePublisher that allows us to move files // instead of leaving them orphaned in the original folder. // TODO: revisit this when ClearCanvas.ImageViewer.StudyManagement.Core.DicomFilePublisher gets an option for moving files public static void PublishLocal(ICollection <DicomFile> files) { if (files == null || files.Count == 0) { return; } var configuration = ClearCanvas.ImageViewer.Common.DicomServer.DicomServer.GetConfiguration(); var context = new ImportStudyContext(configuration.AETitle, StudyStore.GetConfiguration(), EventSource.CurrentUser); var utility = new ImportFilesUtility(context); try { DicomProcessingResult failureResult = null; foreach (var file in files) { var importResult = utility.Import(file, BadFileBehaviourEnum.Move, FileImportBehaviourEnum.Move); // THIS IS THE CHANGE if (importResult.DicomStatus != DicomStatuses.Success) { Platform.Log(LogLevel.Warn, "Unable to import published file: {0}", importResult.ErrorMessage); failureResult = importResult; } } if (failureResult != null) { throw new ApplicationException(failureResult.ErrorMessage); } } catch (Exception ex) { var message = String.Format("Failed to import files"); throw new Exception(message, ex); } }
private bool ImportFiles(IList <string> filePaths, IEnumerable <string> fileExtensions, bool recursive) { var configuration = GetServerConfiguration(); var context = new ImportStudyContext(configuration.AETitle, StudyStore.GetConfiguration(), string.IsNullOrEmpty(Request.UserName) ? EventSource.CurrentProcess : EventSource.GetUserEventSource(Request.UserName)); // Publish the creation of the StudyImport WorkItems lock (context.StudyWorkItemsSyncLock) { context.StudyWorkItems.ItemAdded += (sender, args) => Platform.GetService( (IWorkItemActivityMonitorService service) => service.Publish(new WorkItemPublishRequest { Item = WorkItemDataHelper.FromWorkItem(args.Item) })); context.StudyWorkItems.ItemChanged += (sender, args) => Platform.GetService( (IWorkItemActivityMonitorService service) => service.Publish(new WorkItemPublishRequest { Item = WorkItemDataHelper.FromWorkItem(args.Item) })); } var extensions = new List <string>(); if (fileExtensions != null) { foreach (string extension in fileExtensions) { if (String.IsNullOrEmpty(extension)) { continue; } extensions.Add(extension); } } Progress.PathsToImport = filePaths.Count; bool completedEnumeration = true; foreach (string path in filePaths) { FileProcessor.Process(path, string.Empty, delegate(string file, out bool cancel) { cancel = false; if (CancelPending || StopPending || context.FatalError) { cancel = true; return; } bool enqueue = false; foreach (string extension in extensions) { if (file.EndsWith(extension)) { enqueue = true; break; } } enqueue = enqueue || extensions.Count == 0; if (enqueue) { ++Progress.TotalFilesToImport; Proxy.UpdateProgress(); ImportFile(file, context); } }, recursive); Progress.PathsImported++; Proxy.UpdateProgress(); if (CancelPending || StopPending || context.FatalError) { completedEnumeration = false; } } Progress.CompletedEnumeration = completedEnumeration; return(context.FatalError); }
private void RebuildStudyXml() { try { var studyXml = new StudyXml(Location.Study.StudyInstanceUid); DicomFile lastLoadedFile = null; FileProcessor.Process(Location.StudyFolder, "*.dcm", delegate(string file, out bool cancel) { cancel = _cancelRequested; try { var dicomFile = new DicomFile(file); dicomFile.Load(DicomReadOptions.Default | DicomReadOptions.StorePixelDataReferences); String sopInstanceUid = dicomFile.DataSet[DicomTags.SopInstanceUid].GetString(0, dicomFile.MediaStorageSopInstanceUid); if (Path.GetFileNameWithoutExtension(file) == sopInstanceUid) { if (!studyXml.AddFile(dicomFile)) { Platform.Log(LogLevel.Warn, "Importing file that was in the wrong study folder: {0}", file); var context = new ImportStudyContext(dicomFile.SourceApplicationEntityTitle, StudyStore.GetConfiguration(), EventSource.CurrentProcess); var importer = new ImportFilesUtility(context); var result = importer.Import(dicomFile, BadFileBehaviourEnum.Delete, FileImportBehaviourEnum.Move); if (result.DicomStatus != DicomStatuses.Success) { Platform.Log(LogLevel.Error, "Unable to import file: {0}", result.ErrorMessage); Failed = true; FailureMessage = result.ErrorMessage; } } else { lastLoadedFile = dicomFile; } } else { Platform.Log(LogLevel.Info, "Ignoring duplicate file: {0}", file); } } catch (Exception x) { Platform.Log(LogLevel.Error, x, "Failed to load file for reprocessing: {0}", file); Failed = true; FailureMessage = x.Message; } }, false); // This saves the study Xml to disk, and ensures the database is updated and the study is not marked as "deleted". // If a cancel was requested, don't save the file, and it will remain "as is" if (lastLoadedFile != null && !_cancelRequested) { var p = new ProcessStudyUtility(Location) { IsReprocess = true }; p.ProcessFile(lastLoadedFile, studyXml, null); } } catch (Exception x) { Platform.Log(LogLevel.Error, x, "Unexpected exception reindexing folder: {0}", Location.StudyFolder); Failed = true; FailureMessage = x.Message; } if (_cancelRequested) { Platform.Log(LogLevel.Info, "Cancel requested while rebuilding Study XML in folder: {0}", Location.StudyFolder); } else { Platform.Log(LogLevel.Info, "Rebuilt Study XML for study: {0}", Location.Study.StudyInstanceUid); } }
private void ReprocessFolder() { try { var studyXml = Location.LoadStudyXml(); var fileList = new List <ProcessStudyUtility.ProcessorFile>(); // This code will cleanup a folder and move images around to the proper location. // It in essence allows you to just copy a bunch of files into the filestore, and reindex will clean them up and organize them. FileProcessor.Process(Location.StudyFolder, "*.dcm", delegate(string file, out bool cancel) { cancel = _cancelRequested; try { var dicomFile = new DicomFile(file); dicomFile.Load(DicomReadOptions.StorePixelDataReferences | DicomReadOptions.Default); String studyInstanceUid = dicomFile.DataSet[DicomTags.StudyInstanceUid].GetString(0, string.Empty); if (!Location.Study.StudyInstanceUid.Equals(studyInstanceUid)) { Platform.Log(LogLevel.Warn, "Importing file that was in the wrong study folder: {0}", file); var context = new ImportStudyContext(dicomFile.SourceApplicationEntityTitle, StudyStore.GetConfiguration(), EventSource.CurrentProcess); var importer = new ImportFilesUtility(context); var result = importer.Import(dicomFile, BadFileBehaviourEnum.Delete, FileImportBehaviourEnum.Move); if (!result.DicomStatus.Equals(DicomStatuses.Success)) { try { Platform.Log(LogLevel.Error, "Unable to import file: {0}, deleting: {1}", result.ErrorMessage, file); FileUtils.Delete(file); } catch (Exception x) { Platform.Log(LogLevel.Warn, x, "Unexpected exception deleting file: {0}", file); Failed = true; FailureMessage = x.Message; } } } else { fileList.Add(new ProcessStudyUtility.ProcessorFile(dicomFile, null)); if (fileList.Count > 19) { var p = new ProcessStudyUtility(Location) { IsReprocess = true }; p.ProcessBatch(fileList, studyXml); fileList.Clear(); } } } catch (Exception x) { Platform.Log(LogLevel.Error, "Exception when reindexing {0} files, last file: {1}: {2}", fileList.Count, file, x.Message); fileList.Clear(); // Clear out the failed entries Failed = true; FailureMessage = x.Message; } }, true); if (fileList.Count > 0) { var p = new ProcessStudyUtility(Location) { IsReprocess = true }; p.ProcessBatch(fileList, studyXml); // Now apply Deletion rules var ruleContext = new RulesEngineOptions { ApplyDeleteActions = true, ApplyRouteActions = false }; RulesEngine.Create().ApplyStudyRules(p.StudyLocation.Study.ToStoreEntry(), ruleContext); } } catch (Exception x) { Platform.Log(LogLevel.Error, x, "Unexpected exception reindexing folder: {0}", Location.StudyFolder); Failed = true; FailureMessage = x.Message; } if (_cancelRequested) { Platform.Log(LogLevel.Info, "Cancel requested while reprocessing folder: {0}", Location.StudyFolder); } else { Platform.Log(LogLevel.Info, "Completed reprocessing study folder: {0}", Location.Study.StudyInstanceUid); } }
public override bool OnReceiveRequest(ClearCanvas.Dicom.Network.DicomServer server, ServerAssociationParameters association, byte presentationID, DicomMessage message) { string studyInstanceUid; string seriesInstanceUid; DicomUid sopInstanceUid; bool ok = message.DataSet[DicomTags.SopInstanceUid].TryGetUid(0, out sopInstanceUid); if (ok) { ok = message.DataSet[DicomTags.SeriesInstanceUid].TryGetString(0, out seriesInstanceUid); } if (ok) { ok = message.DataSet[DicomTags.StudyInstanceUid].TryGetString(0, out studyInstanceUid); } if (!ok) { Platform.Log(LogLevel.Error, "Unable to retrieve UIDs from request message, sending failure status."); server.SendCStoreResponse(presentationID, message.MessageId, sopInstanceUid.UID, DicomStatuses.ProcessingFailure); return(true); } if (_importContext == null) { _importContext = new DicomReceiveImportContext(association.CallingAE, GetRemoteHostName(association), StudyStore.GetConfiguration(), EventSource.CurrentProcess); // Publish new WorkItems as they're added to the context lock (_importContext.StudyWorkItemsSyncLock) { _importContext.StudyWorkItems.ItemAdded += delegate(object sender, DictionaryEventArgs <string, WorkItem> args) { Platform.GetService( (IWorkItemActivityMonitorService service) => service.Publish(new WorkItemPublishRequest { Item = WorkItemDataHelper .FromWorkItem( args.Item) })); var auditedInstances = new AuditedInstances(); var request = args.Item.Request as DicomReceiveRequest; if (request != null) { auditedInstances.AddInstance(request.Patient.PatientId, request.Patient.PatientsName, request.Study.StudyInstanceUid); } AuditHelper.LogReceivedInstances( association.CallingAE, GetRemoteHostName(association), auditedInstances, EventSource.CurrentProcess, EventResult.Success, EventReceiptAction.ActionUnknown); } ; _importContext.StudyWorkItems.ItemChanged += (sender, args) => Platform.GetService( (IWorkItemActivityMonitorService service) => service.Publish(new WorkItemPublishRequest { Item = WorkItemDataHelper.FromWorkItem(args.Item) })); } } var importer = new ImportFilesUtility(_importContext); var result = importer.Import(message, BadFileBehaviourEnum.Ignore, FileImportBehaviourEnum.Save); if (result.Successful) { if (!String.IsNullOrEmpty(result.AccessionNumber)) { Platform.Log(LogLevel.Info, "Received SOP Instance {0} from {1} to {2} (A#:{3} StudyUid:{4})", result.SopInstanceUid, association.CallingAE, association.CalledAE, result.AccessionNumber, result.StudyInstanceUid); } else { Platform.Log(LogLevel.Info, "Received SOP Instance {0} from {1} to {2} (StudyUid:{3})", result.SopInstanceUid, association.CallingAE, association.CalledAE, result.StudyInstanceUid); } server.SendCStoreResponse(presentationID, message.MessageId, message.AffectedSopInstanceUid, result.DicomStatus); } else { if (result.DicomStatus == DicomStatuses.ProcessingFailure) { Platform.Log(LogLevel.Error, "Failure importing sop: {0}", result.ErrorMessage); } //OnReceiveError(message, result.ErrorMessage, association.CallingAE); server.SendCStoreResponse(presentationID, message.MessageId, message.AffectedSopInstanceUid, result.DicomStatus, result.ErrorMessage); } return(true); }
protected void LoadImportContext(ServerAssociationParameters association) { _importContext = new DicomReceiveImportContext(association.CallingAE, GetRemoteHostName(association), StudyStore.GetConfiguration(), EventSource.CurrentProcess); // Publish new WorkItems as they're added to the context lock (_importContext.StudyWorkItemsSyncLock) { _importContext.StudyWorkItems.ItemAdded += delegate(object sender, DictionaryEventArgs <string, WorkItem> args) { Platform.GetService( (IWorkItemActivityMonitorService service) => service.Publish(new WorkItemPublishRequest { Item = WorkItemDataHelper.FromWorkItem(args.Item) })); var auditedInstances = new AuditedInstances(); var request = args.Item.Request as DicomReceiveRequest; if (request != null) { auditedInstances.AddInstance(request.Patient.PatientId, request.Patient.PatientsName, request.Study.StudyInstanceUid); } AuditHelper.LogReceivedInstances( association.CallingAE, GetRemoteHostName(association), auditedInstances, EventSource.CurrentProcess, EventResult.Success, EventReceiptAction.ActionUnknown); }; _importContext.StudyWorkItems.ItemChanged += (sender, args) => Platform.GetService( (IWorkItemActivityMonitorService service) => service.Publish(new WorkItemPublishRequest { Item = WorkItemDataHelper.FromWorkItem(args.Item) })); } }
public void Refresh() { _dicomServerConfiguration = DicomServer.GetConfiguration(); _storageConfiguration = StudyStore.GetConfiguration(); }