private InsertWorkItemCommand CreateWorkItemCommand(WorkItem workItem, DicomProcessingResult result, DicomMessageBase file, bool duplicateFile, string duplicateFileName)
        {
            InsertWorkItemCommand insertWorkItemCommand;

            if (duplicateFile)
            {
                insertWorkItemCommand = workItem != null
                                            ? new InsertWorkItemCommand(workItem, result.StudyInstanceUid,
                                                                        result.SeriesInstanceUid, result.SopInstanceUid,
                                                                        duplicateFileName)
                                            : new InsertWorkItemCommand(_context.CreateRequest(file),
                                                                        _context.CreateProgress(), result.StudyInstanceUid,
                                                                        result.SeriesInstanceUid, result.SopInstanceUid,
                                                                        duplicateFileName);
            }
            else
            {
                insertWorkItemCommand = workItem != null
                                            ? new InsertWorkItemCommand(workItem, result.StudyInstanceUid,
                                                                        result.SeriesInstanceUid, result.SopInstanceUid)
                                            : new InsertWorkItemCommand(_context.CreateRequest(file),
                                                                        _context.CreateProgress(), result.StudyInstanceUid,
                                                                        result.SeriesInstanceUid, result.SopInstanceUid);
            }

            insertWorkItemCommand.ExpirationDelaySeconds = _context.ExpirationDelaySeconds;
            return(insertWorkItemCommand);
        }
        private void AuditFailure(DicomProcessingResult result)
        {
            // This primarily happens with DICOMDIR files
            if (string.IsNullOrEmpty(result.StudyInstanceUid))
            {
                return;
            }

            if (!_context.FailedStudyAudits.ContainsKey(result.StudyInstanceUid))
            {
                var auditedInstances = new AuditedInstances();

                auditedInstances.AddInstance(result.PatientId, result.PatientsName,
                                             result.StudyInstanceUid);

                AuditHelper.LogImportStudies(auditedInstances, _context.AuditSource, EventResult.MajorFailure);

                _context.FailedStudyAudits.Add(result.StudyInstanceUid, result.StudyInstanceUid);
            }
        }
Esempio n. 3
0
        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);
                }
            }
            catch (Exception ex)
            {
                var message = string.Format("Failed to import files");
                throw new DicomFilePublishingException(message, ex);
            }
        }
        private void Process(DicomMessageBase message, FileImportBehaviourEnum fileImportBehaviour, WorkItem workItem, DicomProcessingResult result)
        {
            result.Initialize();

            // Use the command processor for rollback capabilities.
            using (var commandProcessor = new ViewerCommandProcessor(String.Format("Processing Sop Instance {0}", result.SopInstanceUid)))
            {
                try
                {
                    var    studyLocation   = new StudyLocation(result.StudyInstanceUid);
                    String destinationFile = studyLocation.GetSopInstancePath(result.SeriesInstanceUid, result.SopInstanceUid);

                    DicomFile file = ConvertToDicomFile(message, destinationFile, _context.SourceAE);

                    // Create the Study Folder, if need be
                    commandProcessor.AddCommand(new CreateDirectoryCommand(studyLocation.StudyFolder));

                    bool   duplicateFile = false;
                    string dupName       = null;

                    if (File.Exists(destinationFile))
                    {
                        // TODO (CR Jun 2012): Shouldn't the commands themselves make this decision at the time
                        // the file is being saved? Otherwise, what happens if the same SOP were being saved 2x simultaneously.
                        // I know the odds are low, but just pointing it out.
                        duplicateFile   = true;
                        dupName         = Guid.NewGuid().ToString() + ".dcm";
                        destinationFile = Path.Combine(Path.GetDirectoryName(destinationFile), dupName);
                    }

                    if (fileImportBehaviour == FileImportBehaviourEnum.Move)
                    {
                        commandProcessor.AddCommand(new RenameFileCommand(file.Filename, destinationFile, true));
                    }
                    else if (fileImportBehaviour == FileImportBehaviourEnum.Copy)
                    {
                        commandProcessor.AddCommand(new CopyFileCommand(file.Filename, destinationFile, true));
                    }
                    else if (fileImportBehaviour == FileImportBehaviourEnum.Save)
                    {
                        commandProcessor.AddCommand(new SaveDicomFileCommand(destinationFile, file, true));
                    }

                    var insertWorkItemCommand = CreateWorkItemCommand(workItem, result, file, duplicateFile, dupName);
                    commandProcessor.AddCommand(insertWorkItemCommand);

                    if (commandProcessor.Execute())
                    {
                        result.DicomStatus = DicomStatuses.Success;
                        IncrementTotalFiles(insertWorkItemCommand, result.StudyInstanceUid);
                    }
                    else
                    {
                        if (commandProcessor.FailureException is ChangeConflictException ||
                            commandProcessor.FailureException is SqlCeLockTimeoutException)
                        {
                            result.RetrySuggested = true;     // Change conflict or lock timeout may work if we just retry
                        }
                        Platform.Log(LogLevel.Warn, "Failure Importing file: {0}", file.Filename);
                        string failureMessage = String.Format(
                            "Failure processing message: {0}. Sending failure status.",
                            commandProcessor.FailureReason);
                        result.SetError(DicomStatuses.ProcessingFailure, failureMessage);

                        // processor already rolled back
                    }
                }
                catch (Exception e)
                {
                    Platform.Log(LogLevel.Error, e, "Unexpected exception when {0}.  Rolling back operation.", commandProcessor.Description);
                    commandProcessor.Rollback();
                    result.SetError(result.DicomStatus ?? DicomStatuses.ProcessingFailure, e.Message);
                }
            }
        }
        private void InsertFailedWorkItemUid(WorkItem workItem, DicomMessageBase message, DicomProcessingResult result, int tryCount = 1)
        {
            if (tryCount < 0)
            {
                tryCount = 1;
            }

            int tries = 0;

            while (tries++ < tryCount)
            {
                using (var commandProcessor = new ViewerCommandProcessor(String.Format("Processing Sop Instance {0}", result.SopInstanceUid)))
                {
                    var fileName = Guid.NewGuid().ToString() + ".dcm";
                    var insertWorkItemCommand = CreateWorkItemCommand(workItem, result, message, true, fileName);
                    //Fail the Uid immediately, since we know the file isn't there.
                    insertWorkItemCommand.WorkItemUid.Failed = true;
                    commandProcessor.AddCommand(insertWorkItemCommand);

                    if (commandProcessor.Execute())
                    {
                        IncrementTotalFiles(insertWorkItemCommand, result.StudyInstanceUid, result.ErrorMessage);
                        return;
                    }
                }

                Thread.Sleep(10);
            }

            Platform.Log(LogLevel.Error, "Failed to insert failed work item UID after {0} attempts (Sop Instance UID={1}).", tries, result.SopInstanceUid);
        }
        /// <summary>
        /// Imports the specified <see cref="DicomMessageBase"/> object into the system.
        /// The object will be inserted into the <see cref="WorkItem"/> for processing
        /// </summary>
        /// <param name="message">The DICOM object to be imported.</param>
        /// <param name="badFileBehavior"> </param>
        /// <param name="fileImportBehaviour"> </param>
        /// <returns>An instance of <see cref="DicomProcessingResult"/> that describes the result of the processing.</returns>
        /// <exception cref="DicomDataException">Thrown when the DICOM object contains invalid data</exception>
        public DicomProcessingResult Import(DicomMessageBase message, BadFileBehaviourEnum badFileBehavior, FileImportBehaviourEnum fileImportBehaviour)
        {
            Platform.CheckForNullReference(message, "message");
            String studyInstanceUid  = message.DataSet[DicomTags.StudyInstanceUid].GetString(0, string.Empty);
            String seriesInstanceUid = message.DataSet[DicomTags.SeriesInstanceUid].GetString(0, string.Empty);
            String sopInstanceUid    = message.DataSet[DicomTags.SopInstanceUid].GetString(0, string.Empty);
            String accessionNumber   = message.DataSet[DicomTags.AccessionNumber].GetString(0, string.Empty);
            String patientsName      = message.DataSet[DicomTags.PatientsName].GetString(0, string.Empty);
            String patientId         = message.DataSet[DicomTags.PatientId].GetString(0, string.Empty);

            var result = new DicomProcessingResult
            {
                Successful        = true,
                StudyInstanceUid  = studyInstanceUid,
                SeriesInstanceUid = seriesInstanceUid,
                SopInstanceUid    = sopInstanceUid,
                AccessionNumber   = accessionNumber,
                PatientsName      = patientsName,
                PatientId         = patientId,
            };

            WorkItem workItem;

            lock (_context.StudyWorkItemsSyncLock)
                _context.StudyWorkItems.TryGetValue(studyInstanceUid, out workItem);

            try
            {
                Validate(message);
            }
            catch (DicomDataException e)
            {
                result.SetError(DicomStatuses.ProcessingFailure, e.Message);
                AuditFailure(result);
                return(result);
            }

            if (workItem != null)
            {
                if (workItem.Status == WorkItemStatusEnum.Deleted || workItem.Status == WorkItemStatusEnum.DeleteInProgress || workItem.Status == WorkItemStatusEnum.Canceled || workItem.Status == WorkItemStatusEnum.Canceling)
                {
                    // TODO Marmot (CR June 2012): not DicomStatuses.Cancel?
                    result.SetError(DicomStatuses.StorageStorageOutOfResources, "Canceled by user");
                    AuditFailure(result);
                    return(result);
                }
            }

            if (LocalStorageMonitor.IsMaxUsedSpaceExceeded)
            {
                //The input to this method is a VALID DICOM file, and we know we should have stored it if it weren't for
                //the fact that we're out of disk space. So, we insert the work item UID anyway, knowing that it'll cause
                //the work item to fail. In fact, that's why we're doing it.
                result.SetError(DicomStatuses.StorageStorageOutOfResources, string.Format("Import failed, disk space usage exceeded"));
                InsertFailedWorkItemUid(workItem, message, result);

                _context.FatalError = true;
                AuditFailure(result);
                return(result);
            }

            Process(message, fileImportBehaviour, workItem, result);

            if (result.DicomStatus != DicomStatuses.Success)
            {
                if (result.RetrySuggested)
                {
                    Platform.Log(LogLevel.Warn,
                                 "Failure importing file with retry suggested, retrying Import of file: {0}",
                                 sopInstanceUid);

                    Process(message, fileImportBehaviour, workItem, result);
                }
            }

            if (result.DicomStatus != DicomStatuses.Success)
            {
                //The input to this method is a VALID DICOM file, and we know we should have stored it if it weren't for
                //the fact that we're out of disk space. So, we insert the work item UID anyway, knowing that it'll cause
                //the work item to fail. In fact, that's why we're doing it.
                InsertFailedWorkItemUid(workItem, message, result);

                AuditFailure(result);
            }

            return(result);
        }