Example #1
0
		/// <summary>
		/// Constructs a new <see cref="SopInstanceNode"/> using the given <see cref="DicomFile"/> as a template.
		/// </summary>
		/// <param name="sourceDicomFile">The <see cref="DicomFile"/> from which to initialize this node.</param>
		public SopInstanceNode(DicomMessageBase sourceDicomFile)
		{
			_dicomFile = new DicomFile("", sourceDicomFile.MetaInfo.Copy(), sourceDicomFile.DataSet.Copy());

			_instanceUid = sourceDicomFile.DataSet[DicomTags.SopInstanceUid].GetString(0, "");
			if (_instanceUid == "")
				_instanceUid = StudyBuilder.NewUid();
		}
Example #2
0
		public DicomCompressCommand(DicomMessageBase file, TransferSyntax syntax, IDicomCodec codec, DicomCodecParameters parms)
			: base("DICOM Compress Command", true)
		{

			_file = file;
			_syntax = syntax;
			_codec = codec;
			_parms = parms;
		}
		public DicomCompressCommand(DicomMessageBase file, XmlDocument parms, bool failOnCodecException)
			: base("DICOM Compress Command", true)
		{
			_file = file;
			_failOnCodecException = failOnCodecException;

			XmlElement element = parms.DocumentElement;

			string syntax = element.Attributes["syntax"].Value;

			_syntax = TransferSyntax.GetTransferSyntax(syntax);
			if (_syntax == null)
			{
				string failureDescription =
					String.Format("Invalid transfer syntax in compression command: {0}", element.Attributes["syntax"].Value);
				Platform.Log(LogLevel.Error, "Error with input syntax: {0}", failureDescription);
				throw new DicomCodecException(failureDescription);
			}

			IDicomCodecFactory[] codecs = DicomCodecRegistry.GetCodecFactories();
			IDicomCodecFactory theCodecFactory = null;
			foreach (IDicomCodecFactory codec in codecs)
				if (codec.CodecTransferSyntax.Equals(_syntax))
				{
					theCodecFactory = codec;
					break;
				}

			if (theCodecFactory == null)
			{
				string failureDescription = String.Format("Unable to find codec for compression: {0}", _syntax.Name);
				Platform.Log(LogLevel.Error, "Error with compression input parameters: {0}", failureDescription);
				throw new DicomCodecException(failureDescription);
			}

			_codec = theCodecFactory.GetDicomCodec();
			_parms = theCodecFactory.GetCodecParameters(parms);
		}
Example #4
0
        /// <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;
        }
Example #5
0
 /// <summary>
 /// Abstract method for creating a <see cref="ProcessStudyRequest"/> object for the given DICOM message.
 /// </summary>
 /// <param name="message"></param>
 /// <returns></returns>
 public abstract ProcessStudyRequest CreateRequest(DicomMessageBase message);
Example #6
0
 public XSopDataSource(DicomMessageBase sourceMessage) : base(sourceMessage)
 {
 }
Example #7
0
        private DicomProcessingResult HandleDuplicateFile(string sopInstanceUid, StudyStorageLocation studyLocation, ServerCommandProcessor commandProcessor, DicomMessageBase message, string sourceFilename, StudyProcessWorkQueueData data)
        {
            Study study = studyLocation.Study ??
                          studyLocation.LoadStudy(ServerExecutionContext.Current.PersistenceContext);

            if (study != null)
            {
                Platform.Log(LogLevel.Info, "Received duplicate SOP {0} (A#:{1} StudyUid:{2}  Patient: {3}  ID:{4})",
                             sopInstanceUid,
                             study.AccessionNumber, study.StudyInstanceUid,
                             study.PatientsName, study.PatientId);
            }
            else
            {
                Platform.Log(LogLevel.Info,
                             "Received duplicate SOP {0} (StudyUid:{1}). Existing files haven't been processed.",
                             sopInstanceUid, studyLocation.StudyInstanceUid);
            }

            var sopProcessingContext = new SopInstanceProcessorContext(commandProcessor, studyLocation, _context.ContextID,
                                                                       _context.Request)
            {
                DuplicateProcessing = _context.DuplicateProcessing
            };
            DicomProcessingResult result = DuplicateSopProcessorHelper.Process(sopProcessingContext, message, data,
                                                                               sourceFilename);

            return(result);
        }
Example #8
0
        private void PopulateStudy(DicomMessageBase response, IEnumerable <DicomTag> tagList, IStudyData row)
        {
            DicomDataset dataSet = response.DataSet;

            dataSet[DicomTags.RetrieveAeTitle].SetStringValue(Partition.AeTitle);

            dataSet[DicomTags.InstanceAvailability].SetStringValue("ONLINE");

            var characterSet = GetPreferredCharacterSet();

            if (!string.IsNullOrEmpty(characterSet))
            {
                dataSet[DicomTags.SpecificCharacterSet].SetStringValue(characterSet);
                dataSet.SpecificCharacterSet = characterSet;
            }

            foreach (DicomTag tag in tagList)
            {
                try
                {
                    switch (tag.TagValue)
                    {
                    case DicomTags.StudyInstanceUid:
                        dataSet[DicomTags.StudyInstanceUid].SetStringValue(row.StudyUid);
                        break;

                    case DicomTags.PatientsName:
                        dataSet[DicomTags.PatientsName].SetStringValue(row.PatientName);
                        break;

                    case DicomTags.PatientId:
                        dataSet[DicomTags.PatientId].SetStringValue(row.PatientId);
                        break;

                    case DicomTags.PatientsBirthDate:
                        dataSet[DicomTags.PatientsBirthDate].SetDateTime(0, row.PatientBirthday);
                        break;

                    case DicomTags.PatientsAge:
                        dataSet[DicomTags.PatientsAge].SetStringValue(row.PatientAge);
                        break;

                    case DicomTags.PatientsSex:
                        dataSet[DicomTags.PatientsSex].SetStringValue(row.PatientSex);
                        break;

                    case DicomTags.StudyDate:
                        dataSet[DicomTags.StudyDate].SetDateTime(0, row.StudyDate);
                        break;

                    case DicomTags.StudyTime:
                        dataSet[DicomTags.StudyTime].SetDateTime(0, row.StudyTime);
                        break;

                    case DicomTags.AccessionNumber:
                        dataSet[DicomTags.AccessionNumber].SetStringValue(row.AccessionNumber);
                        break;

                    case DicomTags.StudyId:
                        dataSet[DicomTags.StudyId].SetStringValue(row.StudyId);
                        break;

                    case DicomTags.StudyDescription:
                        dataSet[DicomTags.StudyDescription].SetStringValue(row.StudyDescription);
                        break;

                    case DicomTags.ReferringPhysiciansName:
                        dataSet[DicomTags.ReferringPhysiciansName].SetStringValue(row.RefPhysician);
                        break;

                    case DicomTags.NumberOfStudyRelatedSeries:
                        dataSet[DicomTags.NumberOfStudyRelatedSeries].AppendInt32(row.NumberOfRelatedSeries);
                        break;

                    case DicomTags.NumberOfStudyRelatedInstances:
                        dataSet[DicomTags.NumberOfStudyRelatedInstances].AppendInt32(
                            row.NumberOfRelatedImage);
                        break;

                    case DicomTags.ModalitiesInStudy:
                        //LoadModalitiesInStudy(read, response, row.Key);
                        break;

                    case DicomTags.QueryRetrieveLevel:
                        dataSet[DicomTags.QueryRetrieveLevel].SetStringValue("STUDY");
                        break;

                    // Meta tags that should have not been in the RQ, but we've already set
                    case DicomTags.RetrieveAeTitle:
                    case DicomTags.InstanceAvailability:
                    case DicomTags.SpecificCharacterSet:
                        break;

                    default:
                        if (!tag.IsPrivate)
                        {
                            dataSet[tag].SetNullValue();
                        }

                        break;
                    }
                }
                catch (Exception e)
                {
                    Log.Logger.Warn("Unexpected error setting tag {0} in C-FIND-RSP",
                                    dataSet[tag].Tag.ToString());
                    if (!tag.IsPrivate)
                    {
                        dataSet[tag].SetNullValue();
                    }
                }
            }
        }
Example #9
0
 public UpdateWorkQueueCommand(DicomMessageBase message,
                               StudyStorageLocation location,
                               bool duplicate)
     : this(message, location, duplicate, null, null)
 {
 }
Example #10
0
 /// <summary>
 /// Constructs a new <see cref="DicomMessageSopDataSource"/>.
 /// </summary>
 /// <param name="sourceMessage">The source <see cref="DicomMessageBase"/> which provides all the SOP instance data.</param>
 protected DicomMessageSopDataSource(DicomMessageBase sourceMessage)
 {
     _dummy = new DicomAttributeCollection();
     SetSourceMessage(sourceMessage);
 }
Example #11
0
 public ServerFilesystemInfo SelectFilesystem(DicomMessageBase msg)
 {
     return(SelectFilesystem());
 }
Example #12
0
 /// <summary>
 /// Inserts a <see cref="DicomMessageBase"/> into the set.
 /// </summary>
 /// <param name="message"></param>
 public void InsertFile(DicomMessageBase message)
 {
     StudyInfo.Add(message);
 }
Example #13
0
        private static ReconcileStudyQueueDescription GetQueueEntryDescription(StudyStorageLocation existingStorage, DicomMessageBase file)
        {
            ReconcileStudyQueueDescription desc = new ReconcileStudyQueueDescription
            {
                ExistingPatientId       = existingStorage.Study.PatientId,
                ExistingPatientName     = existingStorage.Study.PatientsName,
                ExistingAccessionNumber = existingStorage.Study.AccessionNumber,
                ConflictingPatientName  =
                    file.DataSet[DicomTags.PatientsName].GetString(0, String.Empty),
                ConflictingPatientId =
                    file.DataSet[DicomTags.PatientId].GetString(0, String.Empty),
                ConflictingAccessionNumber =
                    file.DataSet[DicomTags.AccessionNumber].GetString(0, String.Empty)
            };

            return(desc);
        }
Example #14
0
        private static IList <StudyHistory> FindReconcileHistories(StudyStorageLocation storageLocation, DicomMessageBase file)
        {
            ImageSetDescriptor fileDesc = new ImageSetDescriptor(file.DataSet);

            List <StudyHistory> studyHistoryList = new List <StudyHistory>(
                ServerHelper.FindStudyHistories(storageLocation.StudyStorage,
                                                new[] { StudyHistoryTypeEnum.StudyReconciled }));

            IList <StudyHistory> reconcileHistories = studyHistoryList.FindAll(
                delegate(StudyHistory item)
            {
                ImageSetDescriptor desc = XmlUtils.Deserialize <ImageSetDescriptor>(item.StudyData.DocumentElement);
                return(desc.Equals(fileDesc));
            });

            if (reconcileHistories.Count == 0)
            {
                // no history found in cache... reload the list and search again one more time
                studyHistoryList = new List <StudyHistory>(
                    ServerHelper.FindStudyHistories(storageLocation.StudyStorage,
                                                    new[] { StudyHistoryTypeEnum.StudyReconciled }));

                reconcileHistories = studyHistoryList.FindAll(
                    delegate(StudyHistory item)
                {
                    ImageSetDescriptor desc = XmlUtils.Deserialize <ImageSetDescriptor>(item.StudyData.DocumentElement);
                    return(desc.Equals(fileDesc));
                });
            }

            return(reconcileHistories);
        }
Example #15
0
		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);
                }
            }
        }
Example #16
0
        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;
        }
Example #17
0
 private void SetSourceMessage(DicomMessageBase sourceMessage)
 {
     _sourceMessage = sourceMessage;
     _loaded        = !_sourceMessage.DataSet.IsEmpty();
 }
Example #18
0
        private void PopulatePatient(DicomMessageBase response, IEnumerable <DicomTag> tagList, IPatientData row)
        {
            DicomDataset dataSet = response.DataSet;

            dataSet[DicomTags.RetrieveAeTitle].SetStringValue(Partition.AeTitle);

            var characterSet = GetPreferredCharacterSet();

            if (!string.IsNullOrEmpty(characterSet))
            {
                dataSet[DicomTags.SpecificCharacterSet].SetStringValue(characterSet);
                dataSet.SpecificCharacterSet = characterSet;
            }

            IList <IStudyData> relatedStudies = row.LoadRelatedStudies();
            IStudyData         studyData      = null;

            if (relatedStudies.Count > 0)
            {
                studyData = relatedStudies.First();
            }

            foreach (DicomTag tag in tagList)
            {
                try
                {
                    switch (tag.TagValue)
                    {
                    case DicomTags.PatientsName:
                        dataSet[DicomTags.PatientsName].SetStringValue(row.PatientName);
                        break;

                    case DicomTags.PatientId:
                        dataSet[DicomTags.PatientId].SetStringValue(row.PatientId);
                        break;

                    case DicomTags.IssuerOfPatientId:
                        dataSet[DicomTags.IssuerOfPatientId].SetStringValue(row.IssuerOfPatientId);
                        break;

                    case DicomTags.NumberOfPatientRelatedStudies:
                        dataSet[DicomTags.NumberOfPatientRelatedStudies].AppendInt32(row.NumberOfRelatedStudies);
                        break;

                    case DicomTags.NumberOfPatientRelatedSeries:
                        dataSet[DicomTags.NumberOfPatientRelatedSeries].AppendInt32(row.NumberOfRelatedSeries);
                        break;

                    case DicomTags.NumberOfPatientRelatedInstances:
                        dataSet[DicomTags.NumberOfPatientRelatedInstances].AppendInt32(
                            row.NumberOfRelatedInstances);
                        break;

                    case DicomTags.QueryRetrieveLevel:
                        dataSet[DicomTags.QueryRetrieveLevel].SetStringValue("PATIENT");
                        break;

                    case DicomTags.PatientsSex:
                        if (studyData == null)
                        {
                            dataSet[DicomTags.PatientsSex].SetNullValue();
                        }
                        else
                        {
                            dataSet[DicomTags.PatientsSex].SetStringValue(studyData.PatientSex);
                        }
                        break;

                    case DicomTags.PatientsBirthDate:
                        if (studyData == null)
                        {
                            dataSet[DicomTags.PatientsBirthDate].SetNullValue();
                        }
                        else
                        {
                            dataSet[DicomTags.PatientsBirthDate].SetDateTime(0, studyData.PatientBirthday);
                        }
                        break;

                    // Meta tags that should have not been in the RQ, but we've already set
                    case DicomTags.RetrieveAeTitle:
                    case DicomTags.InstanceAvailability:
                    case DicomTags.SpecificCharacterSet:
                        break;

                    default:
                        if (!tag.IsPrivate)
                        {
                            dataSet[tag].SetNullValue();
                        }

                        break;
                    }
                }
                catch (Exception e)
                {
                    Log.Logger.Error(e, "Unexpected error setting tag {0} in C-FIND-RSP", dataSet[tag].Tag.ToString());
                    if (!tag.IsPrivate)
                    {
                        dataSet[tag].SetNullValue();
                    }
                }
            }
        }
        /// <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  = 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);
            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;
                    const string extension = null;
                    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);
                        }
                    }

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

                    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);
        }
Example #20
0
        private void PopulateSeries(DicomMessageBase request, DicomMessageBase response, IEnumerable <DicomTag> tagList,
                                    ISeriesData row)
        {
            DicomDataset dataSet = response.DataSet;

            dataSet[DicomTags.RetrieveAeTitle].SetStringValue(Partition.AeTitle);
            dataSet[DicomTags.InstanceAvailability].SetStringValue("ONLINE");

            var characterSet = GetPreferredCharacterSet();

            if (!string.IsNullOrEmpty(characterSet))
            {
                dataSet[DicomTags.SpecificCharacterSet].SetStringValue(characterSet);
                dataSet.SpecificCharacterSet = characterSet;
            }

            foreach (DicomTag tag in tagList)
            {
                try
                {
                    switch (tag.TagValue)
                    {
                    case DicomTags.PatientId:
                        dataSet[DicomTags.PatientId].SetStringValue(request.DataSet[DicomTags.PatientId].ToString());
                        break;

                    case DicomTags.StudyInstanceUid:
                        dataSet[DicomTags.StudyInstanceUid].SetStringValue(
                            request.DataSet[DicomTags.StudyInstanceUid].ToString());
                        break;

                    case DicomTags.SeriesInstanceUid:
                        dataSet[DicomTags.SeriesInstanceUid].SetStringValue(row.SeriesUid);
                        break;

                    case DicomTags.Modality:
                        dataSet[DicomTags.Modality].SetStringValue(row.Modality);
                        break;

                    case DicomTags.SeriesNumber:
                        dataSet[DicomTags.SeriesNumber].SetStringValue(row.SeriesNumber);
                        break;

                    case DicomTags.SeriesDescription:
                        dataSet[DicomTags.SeriesDescription].SetStringValue(row.SeriesDescription);
                        break;

                    case DicomTags.PerformedProcedureStepStartDate:
                        dataSet[DicomTags.PerformedProcedureStepStartDate].SetDateTime(0,
                                                                                       row.PerformedProcedureStepStartDate);
                        break;

                    case DicomTags.PerformedProcedureStepStartTime:
                        dataSet[DicomTags.PerformedProcedureStepStartTime].SetDateTime(0,
                                                                                       row.PerformedProcedureStepStartTime);
                        break;

                    case DicomTags.NumberOfSeriesRelatedInstances:
                        dataSet[DicomTags.NumberOfSeriesRelatedInstances].AppendInt32(row.NumberOfRelatedImage);
                        break;

                    case DicomTags.RequestAttributesSequence:
                        //LoadRequestAttributes(read, response, row);
                        break;

                    case DicomTags.QueryRetrieveLevel:
                        dataSet[DicomTags.QueryRetrieveLevel].SetStringValue("SERIES");
                        break;

                    // Meta tags that should have not been in the RQ, but we've already set
                    case DicomTags.RetrieveAeTitle:
                    case DicomTags.InstanceAvailability:
                    case DicomTags.SpecificCharacterSet:
                        break;

                    default:
                        if (!tag.IsPrivate)
                        {
                            dataSet[tag].SetNullValue();
                        }


                        break;
                    }
                }
                catch (Exception e)
                {
                    Log.Logger.Warn("Unexpected error setting tag {0} in C-FIND-RSP",
                                    dataSet[tag].Tag.ToString());
                    if (!tag.IsPrivate)
                    {
                        dataSet[tag].SetNullValue();
                    }
                }
            }
        }
        private static void Validate(DicomMessageBase message)
        {
            DicomSopInstanceValidator validator = new DicomSopInstanceValidator();

            validator.Validate(message);
        }
Example #22
0
        /// <summary>
        /// Populate the data from a <see cref="Study"/> entity into a DICOM C-FIND-RSP message.
        /// </summary>
        /// <param name="read">The connection to use to read the values.</param>
        /// <param name="response"></param>
        /// <param name="tagList"></param>
        /// <param name="row">The <see cref="Study"/> table to populate the response from.</param>
        /// <param name="availability">Instance availability string.</param>
        private void PopulateStudy(IPersistenceContext read, DicomMessageBase response, IEnumerable <uint> tagList, Study row, string availability)
        {
            DicomAttributeCollection dataSet = response.DataSet;

            dataSet[DicomTags.RetrieveAeTitle].SetStringValue(ServerPartitionMonitor.Instance.FindPartition(row.ServerPartitionKey).AeTitle);

            dataSet[DicomTags.InstanceAvailability].SetStringValue(availability);

            if (false == String.IsNullOrEmpty(row.SpecificCharacterSet))
            {
                dataSet[DicomTags.SpecificCharacterSet].SetStringValue(row.SpecificCharacterSet);
                dataSet.SpecificCharacterSet = row.SpecificCharacterSet; // this will ensure the data is encoded using the specified character set
            }
            foreach (uint tag in tagList)
            {
                try
                {
                    switch (tag)
                    {
                    case DicomTags.StudyInstanceUid:
                        dataSet[DicomTags.StudyInstanceUid].SetStringValue(row.StudyInstanceUid);
                        break;

                    case DicomTags.PatientsName:
                        dataSet[DicomTags.PatientsName].SetStringValue(row.PatientsName);
                        break;

                    case DicomTags.PatientId:
                        dataSet[DicomTags.PatientId].SetStringValue(row.PatientId);
                        break;

                    case DicomTags.PatientsBirthDate:
                        dataSet[DicomTags.PatientsBirthDate].SetStringValue(row.PatientsBirthDate);
                        break;

                    case DicomTags.PatientsAge:
                        dataSet[DicomTags.PatientsAge].SetStringValue(row.PatientsAge);
                        break;

                    case DicomTags.PatientsSex:
                        dataSet[DicomTags.PatientsSex].SetStringValue(row.PatientsSex);
                        break;

                    case DicomTags.StudyDate:
                        dataSet[DicomTags.StudyDate].SetStringValue(row.StudyDate);
                        break;

                    case DicomTags.StudyTime:
                        dataSet[DicomTags.StudyTime].SetStringValue(row.StudyTime);
                        break;

                    case DicomTags.AccessionNumber:
                        dataSet[DicomTags.AccessionNumber].SetStringValue(row.AccessionNumber);
                        break;

                    case DicomTags.StudyId:
                        dataSet[DicomTags.StudyId].SetStringValue(row.StudyId);
                        break;

                    case DicomTags.StudyDescription:
                        dataSet[DicomTags.StudyDescription].SetStringValue(row.StudyDescription);
                        break;

                    case DicomTags.ReferringPhysiciansName:
                        dataSet[DicomTags.ReferringPhysiciansName].SetStringValue(row.ReferringPhysiciansName);
                        break;

                    case DicomTags.NumberOfStudyRelatedSeries:
                        dataSet[DicomTags.NumberOfStudyRelatedSeries].AppendInt32(row.NumberOfStudyRelatedSeries);
                        break;

                    case DicomTags.NumberOfStudyRelatedInstances:
                        dataSet[DicomTags.NumberOfStudyRelatedInstances].AppendInt32(
                            row.NumberOfStudyRelatedInstances);
                        break;

                    case DicomTags.ModalitiesInStudy:
                        LoadModalitiesInStudy(read, response, row.Key);
                        break;

                    case DicomTags.QueryRetrieveLevel:
                        dataSet[DicomTags.QueryRetrieveLevel].SetStringValue("STUDY");
                        break;

                    default:
                        dataSet[tag].SetNullValue();
                        break;

                    // Meta tags that should have not been in the RQ, but we've already set
                    case DicomTags.RetrieveAeTitle:
                    case DicomTags.InstanceAvailability:
                    case DicomTags.SpecificCharacterSet:
                        break;
                    }
                }
                catch (Exception e)
                {
                    Platform.Log(LogLevel.Warn, e, "Unexpected error setting tag {0} in C-FIND-RSP",
                                 dataSet[tag].Tag.ToString());
                    dataSet[tag].SetNullValue();
                }
            }
        }
Example #23
0
        private void HandleNonDuplicateFile(string seriesInstanceUid, string sopInstanceUid, StudyStorageLocation studyLocation, ServerCommandProcessor commandProcessor, DicomMessageBase message, string sourcePath, string path, bool dupImage, StudyProcessWorkQueueData data)
        {
            commandProcessor.AddCommand(new CreateDirectoryCommand(path));

            path = Path.Combine(path, studyLocation.PartitionFolder);
            commandProcessor.AddCommand(new CreateDirectoryCommand(path));

            path = Path.Combine(path, studyLocation.StudyFolder);
            commandProcessor.AddCommand(new CreateDirectoryCommand(path));

            path = Path.Combine(path, studyLocation.StudyInstanceUid);
            commandProcessor.AddCommand(new CreateDirectoryCommand(path));

            path = Path.Combine(path, seriesInstanceUid);
            commandProcessor.AddCommand(new CreateDirectoryCommand(path));

            path  = Path.Combine(path, sopInstanceUid);
            path += ServerPlatform.DicomFileExtension;

            commandProcessor.AddCommand(new RenameFileCommand(sourcePath, path, true));

            WorkQueueUidData uidData = null;

            if (_context.Request != null && !string.IsNullOrEmpty(_context.Request.OperationToken))
            {
                uidData = new WorkQueueUidData
                {
                    OperationToken = _context.Request.OperationToken
                };
            }

            commandProcessor.AddCommand(
                new UpdateWorkQueueCommand(message, studyLocation, dupImage, data, uidData, _context.Request, _context.Priority));

            #region SPECIAL CODE FOR TESTING
            if (Diagnostics.Settings.SimulateFileCorruption)
            {
                commandProcessor.AddCommand(new CorruptDicomFileCommand(path));
            }
            #endregion
        }