public bool CompleteStream(Dicom.Network.DicomServer server, ServerAssociationParameters assoc, byte presentationId, DicomMessage message)
		{
			DicomProcessingResult result;
			var importer = new ImportFilesUtility(_importContext);

			if (_rejectFile)
			{
				result = new DicomProcessingResult();
				result.SetError(DicomStatuses.StorageStorageOutOfResources, string.Format("Import failed, disk space usage exceeded"));

				string studyInstanceUid = message.DataSet[DicomTags.StudyInstanceUid].GetString(0, string.Empty);
				WorkItem workItem;
				lock (_importContext.StudyWorkItemsSyncLock)
					_importContext.StudyWorkItems.TryGetValue(studyInstanceUid, out workItem);

				importer.InsertFailedWorkItemUid(workItem, message, result);

				_importContext.FatalError = true;
				importer.AuditFailure(result);

				Platform.Log(LogLevel.Warn, "Failure receiving sop, out of disk space: {0}", message.AffectedSopInstanceUid);
				server.SendCStoreResponse(presentationId, message.MessageId, message.AffectedSopInstanceUid, result.DicomStatus);
				return true;
			}

			try
			{
				if (_fileStream != null)
				{
					_fileStream.Flush(true);
					_fileStream.Close();
					_fileStream.Dispose();
					_fileStream = null;
				}

				// Convert to file to pass in the source filename
				var theFile = new DicomFile(message,_sourceFilename);

				result = importer.Import(theFile, BadFileBehaviourEnum.Delete, FileImportBehaviourEnum.Move);

				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, assoc.CallingAE, assoc.CalledAE, result.AccessionNumber,
									 result.StudyInstanceUid);
					else
						Platform.Log(LogLevel.Info, "Received SOP Instance {0} from {1} to {2} (StudyUid:{3})",
									 result.SopInstanceUid, assoc.CallingAE, assoc.CalledAE,
									 result.StudyInstanceUid);
				}
			}
			catch (Exception e)
			{
				result = new DicomProcessingResult { DicomStatus = DicomStatuses.ProcessingFailure, ErrorMessage = e.Message };
			}

			if (!result.Successful)
			{
				Platform.Log(LogLevel.Warn, "Failure importing sop: {0}", result.ErrorMessage);
			}

			CleanupFile();

			server.SendCStoreResponse(presentationId, message.MessageId, message.AffectedSopInstanceUid, result.DicomStatus);
			return true;
		}
예제 #2
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) ?? string.Empty, dupName);
					}

					if (fileImportBehaviour == FileImportBehaviourEnum.Move)
					{
						commandProcessor.AddCommand(CommandFactory.CreateRenameFileCommand(file.Filename, destinationFile, true));
					}
					else if (fileImportBehaviour == FileImportBehaviourEnum.Copy)
					{
						commandProcessor.AddCommand(CommandFactory.CreateCopyFileCommand(file.Filename, destinationFile, true));
					}
					else if (fileImportBehaviour == FileImportBehaviourEnum.Save)
					{
						commandProcessor.AddCommand(CommandFactory.CreateSaveDicomFileCommand(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);
				}
			}
		}
예제 #3
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);
                }
            }
        }
예제 #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;
		}
예제 #5
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;
        }