Beispiel #1
0
        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);
            }
        }
Beispiel #2
0
        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();
        }
Beispiel #8
0
        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);
            }
        }
Beispiel #11
0
        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);
            }
        }
Beispiel #14
0
        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);
        }
Beispiel #15
0
        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)
                }));
            }
        }
Beispiel #16
0
 public void Refresh()
 {
     _dicomServerConfiguration = DicomServer.GetConfiguration();
     _storageConfiguration     = StudyStore.GetConfiguration();
 }