private void InsertInstance(DicomFile file)
        {
            StudyStorageLocation location;
            string studyInstanceUid = file.DataSet[DicomTags.StudyInstanceUid].ToString();
            string studyDate        = file.DataSet[DicomTags.StudyDate].ToString();

            using (IUpdateContext context = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush))
            {
                bool created;
                location = FilesystemMonitor.Instance.GetOrCreateWritableStudyStorageLocation(studyInstanceUid,
                                                                                              studyDate,
                                                                                              TransferSyntax.ExplicitVrLittleEndian, context,
                                                                                              _partition,
                                                                                              out created);
                context.Commit();
            }

            using (ServerCommandProcessor processor = new ServerCommandProcessor("Processing WorkQueue DICOM file"))
            {
                try
                {
                    // Insert into the database, but only if its not a duplicate so the counts don't get off
                    InsertInstanceCommand insertInstanceCommand = new InsertInstanceCommand(file, location);
                    processor.AddCommand(insertInstanceCommand);


                    // Do the actual processing
                    if (!processor.Execute())
                    {
                        Platform.Log(LogLevel.Error, "Failure processing command {0} for SOP: {1}", processor.Description, file.MediaStorageSopInstanceUid);
                        Platform.Log(LogLevel.Error, "File that failed processing: {0}", file.Filename);
                        throw new ApplicationException("Unexpected failure (" + processor.FailureReason + ") executing command for SOP: " + file.MediaStorageSopInstanceUid, processor.FailureException);
                    }
                }
                catch (Exception e)
                {
                    Platform.Log(LogLevel.Error, e, "Unexpected exception when {0}.  Rolling back operation.",
                                 processor.Description);
                    processor.Rollback();
                    throw new ApplicationException("Unexpected exception when processing file.", e);
                }
            }
        }
Beispiel #2
0
        private void InsertInstance(DicomFile file, StudyXml stream, WorkQueueUid uid, string deleteFile)
        {
            using (ServerCommandProcessor processor = new ServerCommandProcessor("Processing WorkQueue DICOM file"))
            {
                EventsHelper.Fire(OnInsertingSop, this, new SopInsertingEventArgs {
                    Processor = processor
                });

                InsertInstanceCommand insertInstanceCommand = null;
                InsertStudyXmlCommand insertStudyXmlCommand = null;

                String patientsName = file.DataSet[DicomTags.PatientsName].GetString(0, String.Empty);
                _modality = file.DataSet[DicomTags.Modality].GetString(0, String.Empty);

                if (_context.UpdateCommands.Count > 0)
                {
                    foreach (BaseImageLevelUpdateCommand command in _context.UpdateCommands)
                    {
                        command.File = file;
                        processor.AddCommand(command);
                    }
                }

                try
                {
                    // Create a context for applying actions from the rules engine
                    ServerActionContext context =
                        new ServerActionContext(file, _context.StorageLocation.FilesystemKey, _context.Partition, _context.StorageLocation.Key);
                    context.CommandProcessor = processor;

                    _context.SopCompressionRulesEngine.Execute(context);
                    String seriesUid = file.DataSet[DicomTags.SeriesInstanceUid].GetString(0, String.Empty);
                    String sopUid    = file.DataSet[DicomTags.SopInstanceUid].GetString(0, String.Empty);
                    String finalDest = _context.StorageLocation.GetSopInstancePath(seriesUid, sopUid);

                    if (_context.UpdateCommands.Count > 0)
                    {
                        processor.AddCommand(new SaveDicomFileCommand(_context.StorageLocation, file, file.Filename != finalDest));
                    }
                    else if (file.Filename != finalDest || processor.CommandCount > 0)
                    {
                        // Have to be careful here about failure on exists vs. not failing on exists
                        // because of the different use cases of the importer.
                        // save the file in the study folder, or if its been compressed
                        processor.AddCommand(new SaveDicomFileCommand(finalDest, file, file.Filename != finalDest));
                    }

                    // Update the StudyStream object
                    insertStudyXmlCommand = new InsertStudyXmlCommand(file, stream, _context.StorageLocation);
                    processor.AddCommand(insertStudyXmlCommand);

                    // Have the rules applied during the command processor, and add the objects.
                    processor.AddCommand(new ApplySopRulesCommand(context, _context.SopProcessedRulesEngine));

                    // If specified, delete the file
                    if (deleteFile != null)
                    {
                        processor.AddCommand(new FileDeleteCommand(deleteFile, true));
                    }

                    // Insert into the database, but only if its not a duplicate so the counts don't get off
                    insertInstanceCommand = new InsertInstanceCommand(file, _context.StorageLocation);
                    processor.AddCommand(insertInstanceCommand);

                    // Do a check if the StudyStatus value should be changed in the StorageLocation.  This
                    // should only occur if the object has been compressed in the previous steps.
                    processor.AddCommand(new UpdateStudyStatusCommand(_context.StorageLocation, file));

                    if (uid != null)
                    {
                        processor.AddCommand(new DeleteWorkQueueUidCommand(uid));
                    }

                    // Do the actual processing
                    if (!processor.Execute())
                    {
                        Platform.Log(LogLevel.Error, "Failure processing command {0} for SOP: {1}", processor.Description, file.MediaStorageSopInstanceUid);
                        Platform.Log(LogLevel.Error, "File that failed processing: {0}", file.Filename);
                        throw new ApplicationException("Unexpected failure (" + processor.FailureReason + ") executing command for SOP: " + file.MediaStorageSopInstanceUid, processor.FailureException);
                    }
                    Platform.Log(ServerPlatform.InstanceLogLevel, "Processed SOP: {0} for Patient {1}", file.MediaStorageSopInstanceUid, patientsName);
                }
                catch (Exception e)
                {
                    Platform.Log(LogLevel.Error, e, "Unexpected exception when {0}.  Rolling back operation.",
                                 processor.Description);
                    processor.Rollback();
                    throw new ApplicationException("Unexpected exception when processing file.", e);
                }
                finally
                {
                    if (insertInstanceCommand != null && insertInstanceCommand.Statistics.IsSet)
                    {
                        _instanceStats.InsertDBTime.Add(insertInstanceCommand.Statistics);
                    }
                    if (insertStudyXmlCommand != null && insertStudyXmlCommand.Statistics.IsSet)
                    {
                        _instanceStats.InsertStreamTime.Add(insertStudyXmlCommand.Statistics);
                    }
                }
            }
        }
        /// <summary>
        /// Imports the specified <see cref="DicomMessageBase"/> object into the system.
        /// The object will be inserted into the <see cref="WorkQueue"/> for processing and
        /// if it's a duplicate, proper checks will be done and depending on the policy, it will be
        /// ignored, rejected or inserted into the <see cref="StudyIntegrityQueue"/> for manual intervention.
        /// </summary>
        /// <param name="message">The DICOM object to be imported.</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)
        {
            Platform.CheckForNullReference(message, "message");
            String studyInstanceUid;
            String seriesInstanceUid;
            String sopInstanceUid;
            String accessionNumber;
            String patientsName;

            LoadMessageUids(message, out studyInstanceUid, out seriesInstanceUid, out sopInstanceUid,
                            out accessionNumber, out patientsName);

            DicomFile file = null;

            // Scrub the name for invalid characters.
            string newName = XmlUtils.XmlCharacterScrub(patientsName);

            if (!newName.Equals(patientsName))
            {
                message.DataSet[DicomTags.PatientsName].SetStringValue(newName);
            }

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

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

            // Use the command processor for rollback capabilities.
            using (var commandProcessor = new ServerCommandProcessor(String.Format("Processing Sop Instance {0}", sopInstanceUid)))
            {
                try
                {
                    string failureMessage;
                    StudyStorageLocation studyLocation = GetWritableOnlineStorage(message);

                    // GetWritableOnlineStorage should throw an exception if the study location cannot be found.
                    Platform.CheckForNullReference(studyLocation, "studyLocation");

                    if (!studyLocation.QueueStudyStateEnum.Equals(QueueStudyStateEnum.Idle) &&
                        (!studyLocation.QueueStudyStateEnum.Equals(QueueStudyStateEnum.ProcessingScheduled)))
                    {
                        failureMessage = String.Format("Study {0} on partition {1} is being processed: {2}, can't accept new images.",
                                                       studyLocation.StudyInstanceUid, _context.Partition.Description, studyLocation.QueueStudyStateEnum.Description);
                        result.SetError(DicomStatuses.StorageStorageOutOfResources, failureMessage);
                        return(result);
                    }
                    if (studyLocation.StudyStatusEnum.Equals(StudyStatusEnum.OnlineLossy))
                    {
                        if (studyLocation.IsLatestArchiveLossless)
                        {
                            result.DicomStatus = DicomStatuses.StorageStorageOutOfResources;
                            failureMessage     = String.Format("Study {0} on partition {1} can't accept new images due to lossy compression of the study.  Restoring study.",
                                                               studyLocation.StudyInstanceUid, _context.Partition.Description);
                            Platform.Log(LogLevel.Error, failureMessage);
                            if (ServerHelper.InsertRestoreRequest(studyLocation) == null)
                            {
                                Platform.Log(LogLevel.Warn, "Unable to insert Restore Request for Study");
                            }

                            result.SetError(DicomStatuses.StorageStorageOutOfResources, failureMessage);
                            result.RestoreRequested = true;
                            return(result);
                        }
                    }

                    String path      = studyLocation.FilesystemPath;
                    String finalDest = studyLocation.GetSopInstancePath(seriesInstanceUid, sopInstanceUid);
                    file = ConvertToDicomFile(message, finalDest, _context.SourceAE);

                    if (HasUnprocessedCopy(studyLocation.Key, seriesInstanceUid, sopInstanceUid))
                    {
                        var accept = false;

                        // This is a special case: #10569
                        // Allow user to revive an orphaned study by reprocessing the files found in the filesystem
                        if (File.Exists(finalDest))
                        {
                            accept = DuplicatePolicy.IsParitionDuplicatePolicyOverridden(studyLocation);
                        }

                        if (!accept)
                        {
                            failureMessage = string.Format("Another copy of the SOP Instance was received but has not been processed: {0}", sopInstanceUid);
                            result.SetError(DicomStatuses.DuplicateSOPInstance, failureMessage);
                            return(result);
                        }
                    }

                    var data = new StudyProcessWorkQueueData
                    {
                        ReceivingAeTitle = _context.AlternateAe == null
                                                  ? _context.Partition.AeTitle
                                                  : _context.AlternateAe.AeTitle
                    };

                    if (File.Exists(finalDest))
                    {
                        result = HandleDuplicate(sopInstanceUid, studyLocation, commandProcessor, file, data);
                        if (!result.Successful)
                        {
                            return(result);
                        }
                    }
                    else
                    {
                        HandleNonDuplicate(seriesInstanceUid, sopInstanceUid, studyLocation, commandProcessor, file, path,
                                           false, data);
                    }

                    if (commandProcessor.Execute())
                    {
                        result.DicomStatus = DicomStatuses.Success;
                    }
                    else
                    {
                        failureMessage =
                            String.Format("Failure processing message: {0}. Sending failure status.",
                                          commandProcessor.FailureReason);
                        result.SetError(DicomStatuses.ProcessingFailure, failureMessage);
                        // processor already rolled back
                        return(result);
                    }
                }
                catch (NoWritableFilesystemException)
                {
                    String failureMessage = String.Format("Unable to process image, no writable filesystem found for Study UID {0}.", sopInstanceUid);
                    commandProcessor.Rollback();
                    result.SetError(DicomStatuses.StorageStorageOutOfResources, failureMessage);
                }
                catch (StudyIsNearlineException e)
                {
                    String failureMessage = e.RestoreRequested
                                                ? String.Format("{0}. Restore has been requested.", e.Message)
                                                : e.Message;

                    Platform.Log(LogLevel.Error, failureMessage);
                    commandProcessor.Rollback();
                    result.SetError(DicomStatuses.ProcessingFailure, failureMessage);
                }
                catch (FilesystemNotWritableException)
                {
                    commandProcessor.Rollback();

                    string folder;
                    if (!FilesystemMonitor.Instance.GetWriteableIncomingFolder(_context.Partition, out folder))
                    {
                        String failureMessage =
                            String.Format("Unable to process image, study storage location is missing or not writeable: {0}.", sopInstanceUid);
                        result.SetError(DicomStatuses.StorageStorageOutOfResources, failureMessage);
                        return(result);
                    }

                    if (file == null)
                    {
                        file = ConvertToDicomFile(message, string.Empty, _context.SourceAE);
                    }

                    if (!SaveToFolder(folder, sopInstanceUid, studyInstanceUid, file))
                    {
                        String failureMessage =
                            String.Format("Study storage location not writeable and no writeable incoming folder: {0}.", sopInstanceUid);
                        result.SetError(DicomStatuses.StorageStorageOutOfResources, failureMessage);
                        return(result);
                    }

                    Platform.Log(LogLevel.Info, "Saved existing SOP without writeable storage location to {0} folder: {1}",
                                 FilesystemMonitor.ImportDirectorySuffix, sopInstanceUid);
                    result.DicomStatus = DicomStatuses.Success;
                    return(result);
                }
                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);
                }
            }

            return(result);
        }
Beispiel #4
0
        protected void ProcessFile(Model.WorkQueue item, WorkQueueUid sop, string path, StudyXml studyXml, IDicomCodecFactory theCodecFactory)
        {
            DicomFile file = null;

            _instanceStats = new CompressInstanceStatistics();

            _instanceStats.ProcessTime.Start();

            // Use the command processor for rollback capabilities.
            using (ServerCommandProcessor processor = new ServerCommandProcessor("Processing WorkQueue Compress DICOM File"))
            {
                string modality = String.Empty;

                try
                {
                    file = new DicomFile(path);

                    _instanceStats.FileLoadTime.Start();
                    file.Load(DicomReadOptions.StorePixelDataReferences | DicomReadOptions.Default);
                    _instanceStats.FileLoadTime.End();

                    modality = file.DataSet[DicomTags.Modality].GetString(0, String.Empty);

                    FileInfo fileInfo = new FileInfo(path);
                    _instanceStats.FileSize = (ulong)fileInfo.Length;

                    // Get the Patients Name for processing purposes.
                    String patientsName = file.DataSet[DicomTags.PatientsName].GetString(0, "");

                    if (file.TransferSyntax.Equals(theCodecFactory.CodecTransferSyntax))
                    {
                        // Delete the WorkQueueUid item
                        processor.AddCommand(new DeleteWorkQueueUidCommand(sop));

                        // Do the actual processing
                        if (!processor.Execute())
                        {
                            Platform.Log(LogLevel.Warn, "Failure deleteing WorkQueueUid: {0} for SOP: {1}", processor.Description, file.MediaStorageSopInstanceUid);
                            Platform.Log(LogLevel.Warn, "Compression file that failed: {0}", file.Filename);
                        }
                        else
                        {
                            Platform.Log(LogLevel.Warn, "Skip compressing SOP {0}. Its current transfer syntax is {1}",
                                         file.MediaStorageSopInstanceUid, file.TransferSyntax.Name);
                        }
                    }
                    else
                    {
                        IDicomCodec codec = theCodecFactory.GetDicomCodec();

                        // Create a context for applying actions from the rules engine
                        var context = new ServerActionContext(file, StorageLocation.FilesystemKey, ServerPartition, item.StudyStorageKey);
                        context.CommandProcessor = processor;

                        var parms           = theCodecFactory.GetCodecParameters(item.Data);
                        var compressCommand =
                            new DicomCompressCommand(context.Message, theCodecFactory.CodecTransferSyntax, codec, parms);
                        processor.AddCommand(compressCommand);

                        var save = new SaveDicomFileCommand(file.Filename, file, false);
                        processor.AddCommand(save);

                        // Update the StudyStream object, must be done after compression
                        // and after the compressed image has been successfully saved
                        var insertStudyXmlCommand = new UpdateStudyXmlCommand(file, studyXml, StorageLocation);
                        processor.AddCommand(insertStudyXmlCommand);

                        // Delete the WorkQueueUid item
                        processor.AddCommand(new DeleteWorkQueueUidCommand(sop));

                        // Do the actual processing
                        if (!processor.Execute())
                        {
                            EventManager.FireEvent(this, new FailedUpdateSopEventArgs {
                                File = file, ServerPartitionEntry = context.ServerPartition, WorkQueueUidEntry = sop, WorkQueueEntry = WorkQueueItem, FileLength = (ulong)insertStudyXmlCommand.FileSize, FailureMessage = processor.FailureReason
                            });

                            _instanceStats.CompressTime.Add(compressCommand.CompressTime);
                            Platform.Log(LogLevel.Error, "Failure compressing command {0} for SOP: {1}", processor.Description, file.MediaStorageSopInstanceUid);
                            Platform.Log(LogLevel.Error, "Compression file that failed: {0}", file.Filename);
                            throw new ApplicationException("Unexpected failure (" + processor.FailureReason + ") executing command for SOP: " + file.MediaStorageSopInstanceUid, processor.FailureException);
                        }
                        _instanceStats.CompressTime.Add(compressCommand.CompressTime);
                        Platform.Log(ServerPlatform.InstanceLogLevel, "Compress SOP: {0} for Patient {1}", file.MediaStorageSopInstanceUid,
                                     patientsName);

                        EventManager.FireEvent(this, new UpdateSopEventArgs {
                            File = file, ServerPartitionEntry = context.ServerPartition, WorkQueueUidEntry = sop, WorkQueueEntry = WorkQueueItem, FileLength = (ulong)insertStudyXmlCommand.FileSize
                        });
                    }
                }
                catch (Exception e)
                {
                    EventManager.FireEvent(this, new FailedUpdateSopEventArgs {
                        File = file, ServerPartitionEntry = ServerPartition, WorkQueueUidEntry = sop, WorkQueueEntry = WorkQueueItem, FileLength = (ulong)new FileInfo(path).Length, FailureMessage = processor.FailureReason
                    });

                    Platform.Log(LogLevel.Error, e, "Unexpected exception when {0}.  Rolling back operation.",
                                 processor.Description);
                    processor.Rollback();

                    throw;
                }
                finally
                {
                    _instanceStats.ProcessTime.End();
                    _studyStats.AddSubStats(_instanceStats);

                    _studyStats.StudyInstanceUid = StorageLocation.StudyInstanceUid;
                    if (String.IsNullOrEmpty(modality) == false)
                    {
                        _studyStats.Modality = modality;
                    }

                    // Update the statistics
                    _studyStats.NumInstances++;
                }
            }
        }