public bool GetStreamedFileStorageFolder(DicomMessageBase message, out string folder, out string filesystemStreamingFolder)
        {
            var location = GetWritableOnlineStorage(message);

            using (
                var commandProcessor =
                    new ServerCommandProcessor(String.Format("Streaming folder for Study Instance {0}", location.StudyInstanceUid)))
            {
                String path = Path.Combine(location.FilesystemPath, location.PartitionFolder);
                commandProcessor.AddCommand(new CreateDirectoryCommand(path));

                filesystemStreamingFolder = path = Path.Combine(path, ServerPlatform.StreamingStorageFolder);
                commandProcessor.AddCommand(new CreateDirectoryCommand(path));

                path = Path.Combine(path, _context.ContextID /* the AE title + timestamp */);
                commandProcessor.AddCommand(new CreateDirectoryCommand(path));

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

                if (!commandProcessor.Execute())
                {
                    folder = null;
                    Platform.Log(LogLevel.Warn, "Unable to create directory to store study: {0}: {1}", path,
                                 commandProcessor.FailureReason);
                    return(false);
                }
                folder = path;
                return(true);
            }
        }
Beispiel #2
0
        private void ProcessUid(WorkQueueUid uid)
        {
            Platform.CheckForNullReference(uid, "uid");

            string imagePath = GetUidPath(uid);

            using (ServerCommandProcessor processor = new ServerCommandProcessor(String.Format("Deleting {0}", uid.SopInstanceUid)))
            {
                // If the file for some reason doesn't exist, we just ignore it
                if (File.Exists(imagePath))
                {
                    Platform.Log(ServerPlatform.InstanceLogLevel, "Deleting {0}", imagePath);
                    FileDeleteCommand deleteFile = new FileDeleteCommand(imagePath, true);
                    processor.AddCommand(deleteFile);
                }
                else
                {
                    Platform.Log(LogLevel.Warn, "WARNING {0} is missing.", imagePath);
                }

                DeleteWorkQueueUidCommand deleteUid = new DeleteWorkQueueUidCommand(uid);
                processor.AddCommand(deleteUid);
                if (!processor.Execute())
                {
                    throw new Exception(String.Format("Unable to delete image {0}", uid.SopInstanceUid));
                }
            }
        }
        private ProcessDuplicateResult OverwriteDuplicate(DicomFile dupFile, WorkQueueUid uid, StudyXml studyXml)
        {
            Platform.Log(LogLevel.Info, "Overwriting duplicate SOP {0}", uid.SopInstanceUid);

            var result = new ProcessDuplicateResult();

            result.ActionTaken = DuplicateProcessResultAction.Accept;

            using (var processor = new ServerCommandProcessor("Overwrite duplicate instance"))
            {
                var destination = Context.StorageLocation.GetSopInstancePath(uid.SeriesInstanceUid, uid.SopInstanceUid);
                processor.AddCommand(new RenameFileCommand(dupFile.Filename, destination, false));

                // Ideally we don't need to insert the instance into the database since it's a duplicate.
                // However, we need to do so to ensure the Study record is recreated if we are dealing with an orphan study.
                // For other cases, this will cause the instance count in the DB to be out of sync with the filesystem.
                // But it will be corrected at the end of the processing when the study verification is executed.
                processor.AddCommand(new InsertInstanceCommand(dupFile, Context.StorageLocation));

                // Update the StudyStream object
                processor.AddCommand(new InsertStudyXmlCommand(dupFile, studyXml, Context.StorageLocation));

                processor.AddCommand(new DeleteWorkQueueUidCommand(uid));

                if (!processor.Execute())
                {
                    // cause the item to fail
                    throw new Exception(string.Format("Error occurred when trying to overwrite duplicate in the filesystem."), processor.FailureException);
                }
            }

            return(result);
        }
Beispiel #4
0
        /// <summary>
        /// Create Duplicate SIQ Entry
        /// </summary>
        /// <param name="file"></param>
        /// <param name="location"></param>
        /// <param name="sourcePath"></param>
        /// <param name="queue"></param>
        /// <param name="uid"></param>
        /// <param name="data"></param>
        public static void CreateDuplicateSIQEntry(DicomFile file, StudyStorageLocation location, string sourcePath,
                                                   WorkQueue queue, WorkQueueUid uid, StudyProcessWorkQueueData data)
        {
            Platform.Log(LogLevel.Info, "Creating Work Queue Entry for duplicate...");
            String uidGroup = queue.GroupID ?? queue.GetKey().Key.ToString();

            using (var commandProcessor = new ServerCommandProcessor("Insert Work Queue entry for duplicate"))
            {
                commandProcessor.AddCommand(new FileDeleteCommand(sourcePath, true));

                var sopProcessingContext     = new SopInstanceProcessorContext(commandProcessor, location, uidGroup);
                DicomProcessingResult result = Process(sopProcessingContext, file, data);
                if (!result.Successful)
                {
                    FailUid(uid, true);
                    return;
                }

                commandProcessor.AddCommand(new DeleteWorkQueueUidCommand(uid));

                if (!commandProcessor.Execute())
                {
                    Platform.Log(LogLevel.Error, "Unexpected error when creating duplicate study integrity queue entry: {0}",
                                 commandProcessor.FailureReason);
                    FailUid(uid, true);
                }
            }
        }
        protected override void OnExecute(CommandProcessor theProcessor)
        {
            Platform.CheckForNullReference(Context, "Context");
            Platform.CheckForNullReference(Context.ReconcileWorkQueueData, "Context.ReconcileWorkQueueData");

            foreach (WorkQueueUid uid in Context.WorkQueueUidList)
            {
                string imagePath = GetReconcileUidPath(uid);

                try
                {
                    using (var processor = new ServerCommandProcessor(String.Format("Deleting {0}", uid.SopInstanceUid)))
                    {
                        var deleteFile = new FileDeleteCommand(imagePath, true);
                        var deleteUid  = new DeleteWorkQueueUidCommand(uid);
                        processor.AddCommand(deleteFile);
                        processor.AddCommand(deleteUid);
                        Platform.Log(ServerPlatform.InstanceLogLevel, deleteFile.ToString());
                        if (!processor.Execute())
                        {
                            throw new Exception(String.Format("Unable to discard image {0}", uid.SopInstanceUid));
                        }
                    }
                }
                catch (Exception e)
                {
                    Platform.Log(LogLevel.Error, e, "Unexpected exception discarding file: {0}", imagePath);
                    SopInstanceProcessor.FailUid(uid, true);
                }
            }
        }
Beispiel #6
0
        private static void UpdateNameBasedOnRules(DicomFile file)
        {
            string orginalPatientsNameInFile = file.DataSet[DicomTags.PatientsName].ToString();

            if (String.IsNullOrEmpty(orginalPatientsNameInFile))
            {
                return;
            }

            using (ServerCommandProcessor processor = new ServerCommandProcessor("Update Patient's Name"))
            {
                string normPatName = GetAcceptableName(orginalPatientsNameInFile);

                if (!orginalPatientsNameInFile.Equals(normPatName, StringComparison.InvariantCultureIgnoreCase))
                {
                    processor.AddCommand(new SetTagCommand(file, DicomTags.PatientsName, orginalPatientsNameInFile, normPatName));

                    if (!processor.Execute())
                    {
                        throw new ApplicationException(String.Format("AUTO-CORRECTION Failed: Unable to correct the patient's name in the image. Reason: {0}",
                                                                     processor.FailureReason), processor.FailureException);
                    }
                }
            }

            return;
        }
        /// <summary>
        /// Move the file specified in the path to the incoming folder so that it will be imported again
        /// </summary>
        /// <param name="path"></param>
        private void MoveFileToIncomingFolder(string path)
        {
            Platform.Log(LogLevel.Debug, "Moving file {0} to incoming folder", path);

            // should not proceed because it may mean incomplete study
            if (!File.Exists(path))
            {
                throw new FileNotFoundException(string.Format("File is missing: {0}", path));
            }

            // move the file to the Incoming folder to reprocess
            using (var processor = new ServerCommandProcessor("Move file back to incoming folder"))
            {
                var          fileInfo     = new FileInfo(path);
                const string folder       = "FromWorkQueue";
                var          incomingPath = GetServerPartitionIncomingFolder();
                incomingPath = Path.Combine(incomingPath, "FromWorkQueue");
                incomingPath = Path.Combine(incomingPath, StorageLocation.StudyInstanceUid);

                var createDirCommand = new CreateDirectoryCommand(incomingPath);
                processor.AddCommand(createDirCommand);

                incomingPath = Path.Combine(incomingPath, fileInfo.Name);
                var move = new RenameFileCommand(path, incomingPath, true);
                processor.AddCommand(move);

                if (!processor.Execute())
                {
                    throw new Exception("Unexpected error happened when trying to move file back to the incoming folder for reprocess", processor.FailureException);
                }

                Platform.Log(LogLevel.Info, "File {0} has been moved to the incoming folder.", path);
            }
        }
        protected void RemoveFilesystem()
        {
            string path = StorageLocation.GetStudyPath();

            using (var processor = new ServerCommandProcessor("Delete Filesystems Processor"))
            {
                processor.AddCommand(new DeleteDirectoryCommand(path, true));

                if (_relatedDirectories != null)
                {
                    foreach (DirectoryInfo dir in _relatedDirectories)
                    {
                        processor.AddCommand(new DeleteDirectoryCommand(dir.FullName, true)
                        {
                            Log = true
                        });
                    }
                }

                if (!processor.Execute())
                {
                    throw new ApplicationException(
                              String.Format("Unexpected error when deleting study folders: {0}", processor.FailureReason),
                              processor.FailureException);
                }
            }

            DirectoryUtility.DeleteIfEmpty(Path.GetDirectoryName(path));
        }
 private static void UpdateUidMap(StudyStorageLocation dest, UidMapper uidMapper)
 {
     using (ServerCommandProcessor processor = new ServerCommandProcessor("Update UID Mapping Processor"))
     {
         processor.AddCommand(new SaveUidMapXmlCommand(dest, uidMapper));
         if (!processor.Execute())
         {
             throw new ApplicationException(String.Format("AUTO-RECONCILE Failed: Unable to update uid mapping. Reason: {0}", processor.FailureReason), processor.FailureException);
         }
     }
 }
        private void UpdateStudyOrDuplicates()
        {
            // StorageLocation object must be reloaded if we are overwriting the study
            // with info in the duplicates.
            bool needReload = false;

            switch (_processDuplicateEntry.QueueData.Action)
            {
            case ProcessDuplicateAction.OverwriteUseDuplicates:

                if (_processDuplicateEntry.QueueData.State.ExistingStudyUpdated)
                {
                    Platform.Log(LogLevel.Info, "Existing Study has been updated before");
                }
                else
                {
                    Platform.Log(LogLevel.Info, "Update Existing Study w/ Duplicate Info");
                    _studyUpdateCommands = BuildUpdateStudyCommandsFromDuplicate();
                    using (ServerCommandProcessor processor = new ServerCommandProcessor("Update Existing Study w/ Duplicate Info"))
                    {
                        processor.AddCommand(new UpdateStudyCommand(ServerPartition, StorageLocation, _studyUpdateCommands, ServerRuleApplyTimeEnum.SopProcessed, WorkQueueItem));
                        if (!processor.Execute())
                        {
                            throw new ApplicationException(processor.FailureReason, processor.FailureException);
                        }

                        needReload = true;
                        _processDuplicateEntry.QueueData.State.ExistingStudyUpdated = true;
                    }
                }

                break;

            case ProcessDuplicateAction.OverwriteUseExisting:
                ImageUpdateCommandBuilder commandBuilder = new ImageUpdateCommandBuilder();
                _duplicateUpdateCommands = new List <BaseImageLevelUpdateCommand>();
                _duplicateUpdateCommands.AddRange(commandBuilder.BuildCommands <StudyMatchingMap>(StorageLocation));
                PrintCommands(_duplicateUpdateCommands);
                break;
            }

            if (needReload)
            {
                StudyStorageLocation updatedStorageLocation;

                //NOTE: Make sure we are loading the storage location fro the database instead of the cache.
                if (!FilesystemMonitor.Instance.GetWritableStudyStorageLocation(WorkQueueItem.StudyStorageKey, out updatedStorageLocation))
                {
                    // this is odd.. we just updated it and now it's no longer writable?
                    throw new ApplicationException("Filesystem is not writable");
                }
                StorageLocation = updatedStorageLocation;
            }
        }
Beispiel #11
0
 protected void UpdateHistory(StudyStorageLocation location)
 {
     using (ServerCommandProcessor processor = new ServerCommandProcessor("Reconcile-CreateStudy-Update History"))
     {
         processor.AddCommand(new SaveUidMapXmlCommand(location, UidMapper));
         processor.AddCommand(new UpdateHistorySeriesMappingCommand(Context.History, location, UidMapper));
         if (!processor.Execute())
         {
             throw new ApplicationException("Unable to update the history", processor.FailureException);
         }
     }
 }
        private static void OnStudyRestored(StudyStorageLocation location)
        {
            ValidateStudy(location);

            using (var processor = new ServerCommandProcessor("Update Study Size In DB"))
            {
                processor.AddCommand(new UpdateStudySizeInDBCommand(location));
                if (!processor.Execute())
                {
                    Platform.Log(LogLevel.Error, "Unexpected error when trying to update the study size in DB:", processor.FailureReason);
                }
            }
        }
        void SaveDuplicateReport(WorkQueueUid uid, string sourceFile, string destinationFile, DicomFile dupFile, StudyXml studyXml)
        {
            using (var processor = new ServerCommandProcessor("Save duplicate report"))
            {
                processor.AddCommand(new RenameFileCommand(sourceFile, destinationFile, false));

                // Update the StudyStream object
                processor.AddCommand(new InsertStudyXmlCommand(dupFile, studyXml, Context.StorageLocation));

                processor.AddCommand(new DeleteWorkQueueUidCommand(uid));

                processor.Execute();
            }
        }
Beispiel #14
0
        /// <summary>
        /// Apply the Rules engine.
        /// </summary>
        /// <remarks>
        /// <para>
        /// This method applies the rules engine to the first image in each series within a study.
        /// The assumption is that the actions generated by the engine can handle being applied more
        /// than once for the same study.  This is also done to handle the case of multi-modality
        /// studies where you may want the rules to be run against each series, because they may
        /// apply differently.
        /// </para>
        /// <para>
        /// Note that we are still applying series level moves, although there currently are not
        /// any series level rules.  We've somewhat turned the study level rules into series
        /// level rules.
        /// </para>
        /// </remarks>
        public void Apply(ServerRuleApplyTimeEnum applyTime)
        {
            using (var theProcessor = new ServerCommandProcessor("Study Rule Processor"))
            {
                Apply(applyTime, theProcessor);

                if (false == theProcessor.Execute())
                {
                    Platform.Log(LogLevel.Error,
                                 "Unexpected failure processing Study level rules for study {0} on partition {1} for {2} apply time",
                                 _location.StudyInstanceUid, _partition.Description, applyTime.Description);
                }
            }
        }
Beispiel #15
0
 private void UpdateExistingStudy()
 {
     Platform.Log(LogLevel.Info, "Updating existing study...");
     using (ServerCommandProcessor updateProcessor = new ServerCommandProcessor("Update Study"))
     {
         UpdateStudyCommand studyUpdateCommand = new UpdateStudyCommand(Context.Partition, _destinationStudyStorage, _commands, ServerRuleApplyTimeEnum.SopProcessed, Context.WorkQueueItem);
         updateProcessor.AddCommand(studyUpdateCommand);
         if (!updateProcessor.Execute())
         {
             throw new ApplicationException(
                       String.Format("Unable to update existing study: {0}", updateProcessor.FailureReason));
         }
     }
 }
 private void DeleteDuplicate(WorkQueueUid uid)
 {
     using (ServerCommandProcessor processor = new ServerCommandProcessor("Delete Received Duplicate"))
     {
         FileInfo duplicateFile = GetDuplicateSopFile(uid);
         processor.AddCommand(new FileDeleteCommand(duplicateFile.FullName, true));
         processor.AddCommand(new DeleteWorkQueueUidCommand(uid));
         if (!processor.Execute())
         {
             throw new ApplicationException(processor.FailureReason, processor.FailureException);
         }
         Platform.Log(ServerPlatform.InstanceLogLevel, "Discard duplicate SOP {0} in {1}", uid.SopInstanceUid, duplicateFile.FullName);
     }
 }
Beispiel #17
0
        public void OnStudyDeleting()
        {
            if (!Enabled)
            {
                return;
            }

            StudyStorageLocation        storage  = _context.StorageLocation;
            IList <ArchiveStudyStorage> archives = StudyStorageLocation.GetArchiveLocations(storage.GetKey());

            if (archives != null && archives.Count > 0)
            {
                _archives = new DeletedStudyArchiveInfoCollection();
                foreach (ArchiveStudyStorage archive in archives)
                {
                    DeletedStudyArchiveInfo archiveInfo = new DeletedStudyArchiveInfo();
                    archiveInfo.ArchiveTime = archive.ArchiveTime;
                    archiveInfo.ArchiveXml  = archive.ArchiveXml;

                    archiveInfo.PartitionArchiveRef = PartitionArchive.Load(archive.PartitionArchiveKey).GetKey().Key;
                    archiveInfo.TransferSyntaxUid   = archive.ServerTransferSyntax.Uid;
                    _archives.Add(archiveInfo);
                }
            }



            // only backup if study is manually deleted
            if (_context.WorkQueueItem.WorkQueueTypeEnum == WorkQueueTypeEnum.WebDeleteStudy)
            {
                using (var processor = new ServerCommandProcessor("Backup deleted study"))
                {
                    string path = _context.Filesystem.ResolveAbsolutePath(BackupSubPath);

                    Platform.Log(LogLevel.Info, "Saving a copy of the study to {0}...", path);

                    var mkdir = new CreateDirectoryCommand(path);
                    processor.AddCommand(mkdir);

                    var zip = new ZipStudyFolderCommand(storage.GetStudyPath(), BackupFullPath);
                    processor.AddCommand(zip);

                    if (!processor.Execute())
                    {
                        throw new ApplicationException(String.Format("Unable to backup study: {0}", processor.FailureReason));
                    }
                }
            }
        }
        /// <summary>
        /// Overwrites existing copy with the received duplicate. Update the database, study xml and applies any SOP rules.
        /// </summary>
        /// <param name="dupFile"></param>
        /// <param name="uid"></param>
        /// <param name="studyXml"></param>
        /// <returns></returns>
        private ProcessDuplicateResult OverwriteAndUpdateDuplicate(DicomFile dupFile, WorkQueueUid uid, StudyXml studyXml)
        {
            Platform.Log(LogLevel.Info, "Overwriting duplicate SOP {0}", uid.SopInstanceUid);

            var result = new ProcessDuplicateResult();

            result.ActionTaken = DuplicateProcessResultAction.Accept;

            using (var processor = new ServerCommandProcessor("Overwrite duplicate instance"))
            {
                var sopContext = new ServerActionContext(dupFile, Context.StorageLocation.FilesystemKey, Context.StorageLocation.ServerPartition, Context.StorageLocation.Key, processor);

                var destination = Context.StorageLocation.GetSopInstancePath(uid.SeriesInstanceUid, uid.SopInstanceUid);
                processor.AddCommand(new RenameFileCommand(dupFile.Filename, destination, false));

                // Do so that the FileSize calculation inInsertStudyXmlCommand works
                dupFile.Filename = destination;

                // Update the StudyStream object
                var insertStudyXmlCommand = new InsertStudyXmlCommand(dupFile, studyXml, Context.StorageLocation);
                processor.AddCommand(insertStudyXmlCommand);

                // Ideally we don't need to insert the instance into the database since it's a duplicate.
                // However, we need to do so to ensure the Study record is recreated if we are dealing with an orphan study.
                // For other cases, this will cause the instance count in the DB to be out of sync with the filesystem.
                // But it will be corrected at the end of the processing when the study verification is executed.
                processor.AddCommand(new UpdateInstanceCommand(Context.StorageLocation.ServerPartition, Context.StorageLocation, dupFile));

                processor.AddCommand(new DeleteWorkQueueUidCommand(uid));

                processor.AddCommand(new ApplySopRulesCommand(sopContext, Context.SopProcessedRulesEngine));

                if (!processor.Execute())
                {
                    EventManager.FireEvent(this, new FailedUpdateSopEventArgs {
                        File = dupFile, ServerPartitionEntry = Context.StorageLocation.ServerPartition, WorkQueueUidEntry = uid, WorkQueueEntry = WorkQueueItem, FileLength = (ulong)insertStudyXmlCommand.FileSize, FailureMessage = processor.FailureReason
                    });

                    // cause the item to fail
                    throw new Exception(string.Format("Error occurred when trying to overwrite duplicate in the filesystem."), processor.FailureException);
                }

                EventManager.FireEvent(this, new UpdateSopEventArgs {
                    File = dupFile, ServerPartitionEntry = Context.StorageLocation.ServerPartition, WorkQueueUidEntry = uid, WorkQueueEntry = WorkQueueItem, FileLength = (ulong)insertStudyXmlCommand.FileSize
                });
            }

            return(result);
        }
        private static void UpdateImage(DicomFile file, IEnumerable <BaseImageLevelUpdateCommand> commands)
        {
            using (ServerCommandProcessor processor = new ServerCommandProcessor("Update Image According to History"))
            {
                foreach (BaseImageLevelUpdateCommand cmd in commands)
                {
                    cmd.File = file;
                    processor.AddCommand(cmd);
                }

                if (!processor.Execute())
                {
                    throw new ApplicationException(String.Format("AUTO-RECONCILE Failed: Unable to update image to match target study. Reason: {0}", processor.FailureReason), processor.FailureException);
                }
            }
        }
Beispiel #20
0
        private void SaveFile(DicomFile file)
        {
            String seriesInstanceUid = file.DataSet[DicomTags.SeriesInstanceUid].GetString(0, String.Empty);
            String sopInstanceUid    = file.DataSet[DicomTags.SopInstanceUid].GetString(0, String.Empty);

            String destPath = _oldStudyLocation.FilesystemPath;

            using (ServerCommandProcessor filesystemUpdateProcessor = new ServerCommandProcessor("Update Study"))
            {
                filesystemUpdateProcessor.AddCommand(new CreateDirectoryCommand(destPath));

                destPath = Path.Combine(destPath, _partition.PartitionFolder);
                filesystemUpdateProcessor.AddCommand(new CreateDirectoryCommand(destPath));

                destPath = Path.Combine(destPath, _oldStudyFolder);
                filesystemUpdateProcessor.AddCommand(new CreateDirectoryCommand(destPath));

                destPath = Path.Combine(destPath, _newStudyInstanceUid);
                filesystemUpdateProcessor.AddCommand(new CreateDirectoryCommand(destPath));

                destPath = Path.Combine(destPath, seriesInstanceUid);
                filesystemUpdateProcessor.AddCommand(new CreateDirectoryCommand(destPath));

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

                // Overwrite the prior file
                SaveDicomFileCommand saveCommand = new SaveDicomFileCommand(destPath, file, false);
                filesystemUpdateProcessor.AddCommand(saveCommand);

                if (_rulesEngine != null)
                {
                    ServerActionContext context = new ServerActionContext(file, _oldStudyLocation.FilesystemKey, _partition, _oldStudyLocation.Key)
                    {
                        CommandProcessor = filesystemUpdateProcessor
                    };
                    _rulesEngine.Execute(context);
                }

                if (!filesystemUpdateProcessor.Execute())
                {
                    throw new ApplicationException(String.Format("Unable to update image {0} : {1}", file.Filename, filesystemUpdateProcessor.FailureReason));
                }
            }
        }
        private static void RemoveWorkQueueUid(WorkQueueUid uid, string fileToDelete)
        {
            using (var processor = new ServerCommandProcessor("Remove Work Queue Uid"))
            {
                processor.AddCommand(new DeleteWorkQueueUidCommand(uid));
                if (String.IsNullOrEmpty(fileToDelete) == false)
                {
                    processor.AddCommand(new FileDeleteCommand(fileToDelete, true));
                }

                if (!processor.Execute())
                {
                    String error = String.Format("Unable to delete Work Queue Uid {0}: {1}", uid.Key, processor.FailureReason);
                    Platform.Log(LogLevel.Error, error);
                    throw new ApplicationException(error, processor.FailureException);
                }
            }
        }
Beispiel #22
0
        private void CreateDestinationStudyStorage()
        {
            // This really should never happen;
            if (Context.History.DestStudyStorageKey != null)
            {
                _destinationStudyStorage =
                    StudyStorageLocation.FindStorageLocations(StudyStorage.Load(Context.History.DestStudyStorageKey))[0];
                return;
            }

            string newStudyInstanceUid = string.Empty;

            // Get the new Study Instance Uid by looking through the update commands
            foreach (BaseImageLevelUpdateCommand command in Commands)
            {
                SetTagCommand setTag = command as SetTagCommand;
                if (setTag != null && setTag.Tag.TagValue.Equals(DicomTags.StudyInstanceUid))
                {
                    newStudyInstanceUid = setTag.Value;
                    break;
                }
            }

            if (string.IsNullOrEmpty(newStudyInstanceUid))
            {
                throw new ApplicationException("Unexpectedly could not find new Study Instance Uid value for Create Study");
            }


            using (ServerCommandProcessor processor = new ServerCommandProcessor("Reconciling image processor"))
            {
                // Assign new series and instance uid
                InitializeStorageCommand command = new InitializeStorageCommand(Context, newStudyInstanceUid, Context.WorkQueueItemStudyStorage.StudyFolder,
                                                                                TransferSyntax.GetTransferSyntax(Context.WorkQueueItemStudyStorage.TransferSyntaxUid));
                processor.AddCommand(command);

                if (!processor.Execute())
                {
                    throw new ApplicationException(String.Format("Unable to create Study Storage for study: {0}", newStudyInstanceUid), processor.FailureException);
                }

                _destinationStudyStorage = command.Location;
            }
        }
        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);
                }
            }
        }
        private void RemoveExistingImage(WorkQueueUid uid)
        {
            string path = StorageLocation.GetSopInstancePath(uid.SeriesInstanceUid, uid.SopInstanceUid);

            if (!File.Exists(path))
            {
                return;
            }

            StudyXml studyXml = StorageLocation.LoadStudyXml();
            var      file     = new DicomFile(path);

            file.Load(DicomReadOptions.DoNotStorePixelDataInDataSet | DicomReadOptions.Default); // don't need to load pixel data cause we will delete it

            #if DEBUG
            int originalInstanceCountInXml  = studyXml.NumberOfStudyRelatedInstances;
            int originalStudyInstanceCount  = Study.NumberOfStudyRelatedInstances;
            int originalSeriesInstanceCount = Study.Series[uid.SeriesInstanceUid].NumberOfSeriesRelatedInstances;
            #endif

            using (var processor = new ServerCommandProcessor("Delete Existing Image"))
            {
                var seriesInstanceUid = file.DataSet[DicomTags.SeriesInstanceUid].ToString();
                var sopInstanceUid    = file.DataSet[DicomTags.SopInstanceUid].ToString();

                processor.AddCommand(new FileDeleteCommand(path, true));
                processor.AddCommand(new RemoveInstanceFromStudyXmlCommand(StorageLocation, studyXml, seriesInstanceUid, sopInstanceUid));
                processor.AddCommand(new UpdateInstanceCountCommand(StorageLocation, seriesInstanceUid, sopInstanceUid));

                if (!processor.Execute())
                {
                    throw new ApplicationException(String.Format("Unable to remove existing image {0}", file.Filename), processor.FailureException);
                }
            }

            #if DEBUG
            Debug.Assert(!File.Exists(path));
            Debug.Assert(studyXml.NumberOfStudyRelatedInstances == originalInstanceCountInXml - 1);
            Debug.Assert(Study.Load(Study.Key).NumberOfStudyRelatedInstances == originalStudyInstanceCount - 1);
            Debug.Assert(Study.Load(Study.Key).Series[uid.SeriesInstanceUid].NumberOfSeriesRelatedInstances == originalSeriesInstanceCount - 1);
            #endif
        }
        void CreateDuplicateSIQEntry(WorkQueueUid uid, DicomFile file, List <DicomAttributeComparisonResult> differences)
        {
            Platform.Log(LogLevel.Info, "Duplicate SOP is different from existing copy. Creating duplicate SIQ entry. SOP: {0}", uid.SopInstanceUid);

            using (var processor = new ServerCommandProcessor("Create Duplicate SIQ Entry"))
            {
                var insertCommand = new InsertOrUpdateEntryCommand(
                    uid.GroupID, StorageLocation, file,
                    ServerPlatform.GetDuplicateGroupPath(StorageLocation, uid),
                    string.IsNullOrEmpty(uid.RelativePath)
                        ? Path.Combine(StorageLocation.StudyInstanceUid, uid.SopInstanceUid + "." + uid.Extension)
                        : uid.RelativePath,
                    differences);
                processor.AddCommand(insertCommand);

                processor.AddCommand(new DeleteWorkQueueUidCommand(uid));

                processor.Execute();
            }
        }
        void SaveDuplicateReport(WorkQueueUid uid, string sourceFile, string destinationFile, DicomFile dupFile, StudyXml studyXml)
        {
            using (var processor = new ServerCommandProcessor("Save duplicate report"))
            {
                var sopContext = new ServerActionContext(dupFile, Context.StorageLocation.FilesystemKey, Context.StorageLocation.ServerPartition, Context.StorageLocation.Key, processor);

                processor.AddCommand(new RenameFileCommand(sourceFile, destinationFile, false));

                // Update the StudyStream object
                processor.AddCommand(new InsertStudyXmlCommand(dupFile, studyXml, Context.StorageLocation));

                // Update the series
                processor.AddCommand(new UpdateSeriesCommand(Context.StorageLocation, sopContext));

                processor.AddCommand(new DeleteWorkQueueUidCommand(uid));

                processor.AddCommand(new ApplySopRulesCommand(sopContext, Context.SopProcessedRulesEngine));

                processor.Execute();
            }
        }
        private static bool SaveToFolder(string folder, string sopInstanceUid, string studyInstanceUid, DicomFile file)
        {
            using (var commandProcessor =
                       new ServerCommandProcessor(String.Format("Saving Sop Instance to Incoming {0}", sopInstanceUid)))
            {
                string path = Path.Combine(folder, studyInstanceUid);
                commandProcessor.AddCommand(new CreateDirectoryCommand(path));

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

                if (File.Exists(path))
                {
                    return(false);
                }

                commandProcessor.AddCommand(new SaveDicomFileCommand(path, file, true));

                return(commandProcessor.Execute());
            }
        }
Beispiel #28
0
        private bool UpdateNameBasedOnTheStudy(DicomFile file)
        {
            bool   updated = false;
            string orginalPatientsNameInFile = file.DataSet[DicomTags.PatientsName].ToString();

            if (_theStudy == null)
            {
                return(false);
            }

            StudyComparer        comparer  = new StudyComparer();
            ServerPartition      partition = ServerPartitionMonitor.Instance.FindPartition(_theStudy.ServerPartitionKey);
            DifferenceCollection list      = comparer.Compare(file, _theStudy, partition.GetComparisonOptions());

            if (list.Count == 1)
            {
                ComparisionDifference different = list[0];
                if (different.DicomTag.TagValue == DicomTags.PatientsName)
                {
                    if (DicomNameUtils.LookLikeSameNames(orginalPatientsNameInFile, _theStudy.PatientsName))
                    {
                        using (ServerCommandProcessor processor = new ServerCommandProcessor("Update Patient's Name"))
                        {
                            SetTagCommand command = new SetTagCommand(file, DicomTags.PatientsName, orginalPatientsNameInFile, _theStudy.PatientsName);
                            processor.AddCommand(command);

                            if (!processor.Execute())
                            {
                                throw new ApplicationException(String.Format("AUTO-CORRECTION Failed: Unable to correct the patient's name in the image. Reason: {0}",
                                                                             processor.FailureReason), processor.FailureException);
                            }

                            updated = true;
                        }
                    }
                }
            }
            return(updated);
        }
Beispiel #29
0
        /// <summary>
        /// Inserts a <see cref="StudyIntegrityQueue"/> entry for manual reconciliation.
        /// </summary>
        /// <param name="file">The DICOM file that needs to be reconciled.</param>
        /// <param name="reason">The type of <see cref="StudyIntegrityQueue"/> entry to be inserted.</param>
        /// <param name="uid">A UID to delete on insert.</param>
        /// <remarks>
        /// A copy of the DICOM file will be stored in a special folder allocated for
        /// reconciliation purpose. The caller is responsible for managing the original copy.
        /// </remarks>
        public void ScheduleReconcile(DicomFile file, StudyIntegrityReasonEnum reason, WorkQueueUid uid)
        {
            Platform.CheckForNullReference(_context.StudyLocation, "_context.StudyLocation");

            Platform.Log(LogLevel.Info, "Scheduling new manual reconciliation for SOP {0}", file.MediaStorageSopInstanceUid);
            ServerFilesystemInfo fs = FilesystemMonitor.Instance.GetFilesystemInfo(_context.StudyLocation.FilesystemKey);

            Platform.CheckForNullReference(fs, "fs");

            ReconcileStorage reconcileStorage = new ReconcileStorage(_context.StudyLocation, _context.Group);

            using (ServerCommandProcessor processor = new ServerCommandProcessor("Schedule Manual Reconciliation"))
            {
                string        path = reconcileStorage.GetSopInstancePath(file.DataSet[DicomTags.SopInstanceUid].ToString());
                DirectoryInfo dir  = new DirectoryInfo(path);
                if (dir.Parent != null)
                {
                    CreateDirectoryCommand mkdir = new CreateDirectoryCommand(dir.Parent.FullName);
                    processor.AddCommand(mkdir);
                }

                SaveDicomFileCommand saveFileCommand = new SaveDicomFileCommand(path, file, true);
                processor.AddCommand(saveFileCommand);

                InsertSIQCommand updateStudyCommand = new InsertSIQCommand(_context.StudyLocation, reason, file, _context.Group, reconcileStorage);
                processor.AddCommand(updateStudyCommand);

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

                if (processor.Execute() == false)
                {
                    throw new ApplicationException(String.Format("Unable to schedule image reconcilation : {0}", processor.FailureReason), processor.FailureException);
                }
            }
        }
Beispiel #30
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>
		/// Archive the specified <see cref="ArchiveQueue"/> item.
		/// </summary>
		/// <param name="queueItem">The ArchiveQueue item to archive.</param>
		public void Run(ArchiveQueue queueItem)
		{
            using (ArchiveProcessorContext executionContext = new ArchiveProcessorContext(queueItem))
            {
                try
                {
				    if (!_nasArchive.CheckStudyDiskSpace())
                    {
                        queueItem.FailureDescription = "Not enough free disk space.";
                        _nasArchive.UpdateArchiveQueue(queueItem, ArchiveQueueStatusEnum.Pending, Platform.Time.AddMinutes(60));
                        return;
                    }                    
					
                    if (!GetStudyStorageLocation(queueItem))
                    {
                        Platform.Log(LogLevel.Error,
                                     "Unable to find readable study storage location for archival queue request {0}.  Delaying request.",
                                     queueItem.Key);
                        queueItem.FailureDescription = "Unable to find readable study storage location for archival queue request.";
                        _nasArchive.UpdateArchiveQueue(queueItem, ArchiveQueueStatusEnum.Pending, Platform.Time.AddMinutes(2));
                        return;
                    }

                    // First, check to see if we can lock the study, if not just reschedule the queue entry.
                    if (!_storageLocation.QueueStudyStateEnum.Equals(QueueStudyStateEnum.Idle))
                    {
                        Platform.Log(LogLevel.Info, "Study {0} on partition {1} is currently locked, delaying archival.", _storageLocation.StudyInstanceUid, _nasArchive.ServerPartition.Description);
                        queueItem.FailureDescription = "Study is currently locked, delaying archival.";
                        _nasArchive.UpdateArchiveQueue(queueItem, ArchiveQueueStatusEnum.Pending, Platform.Time.AddMinutes(2));
                        return;
                    }

                    StudyIntegrityValidator validator = new StudyIntegrityValidator();
                    validator.ValidateStudyState("Archive", _storageLocation, StudyIntegrityValidationModes.Default);

                    using (IUpdateContext update = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush))
                    {
                        ILockStudy studyLock = update.GetBroker<ILockStudy>();
                        LockStudyParameters parms = new LockStudyParameters
                                                    	{
                                                    		StudyStorageKey = queueItem.StudyStorageKey,
                                                    		QueueStudyStateEnum = QueueStudyStateEnum.ArchiveScheduled
                                                    	};
                    	bool retVal = studyLock.Execute(parms);
                        if (!parms.Successful || !retVal)
                        {
                            Platform.Log(LogLevel.Info, "Study {0} on partition {1} failed to lock, delaying archival.", _storageLocation.StudyInstanceUid, _nasArchive.ServerPartition.Description);
                            queueItem.FailureDescription = "Study failed to lock, delaying archival.";
                            _nasArchive.UpdateArchiveQueue(queueItem, ArchiveQueueStatusEnum.Pending, Platform.Time.AddMinutes(2));
                            return;
                        }
                        update.Commit();
                    }

                    string studyFolder = _storageLocation.GetStudyPath();

                    string studyXmlFile = _storageLocation.GetStudyXmlPath(); 
                    
                    // Load the study Xml file, this is used to generate the list of dicom files to archive.
                    LoadStudyXml(studyXmlFile);

                    DicomFile file = LoadFileFromStudyXml();

                	string patientsName = file.DataSet[DicomTags.PatientsName].GetString(0, string.Empty);
					string patientId = file.DataSet[DicomTags.PatientId].GetString(0, string.Empty);
					string accessionNumber = file.DataSet[DicomTags.AccessionNumber].GetString(0, string.Empty);

                	Platform.Log(LogLevel.Info,
                	             "Starting archival of study {0} for Patient {1} (PatientId:{2} A#:{3}) on Partition {4} on archive {5}",
                	             _storageLocation.StudyInstanceUid, patientsName, patientId,
                	             accessionNumber, _nasArchive.ServerPartition.Description,
                	             _nasArchive.PartitionArchive.Description);

                    // Use the command processor to do the archival.
                    using (ServerCommandProcessor commandProcessor = new ServerCommandProcessor("Archive"))
                    {
                        _archiveXml = new XmlDocument();

                        // Create the study date folder
                        string zipFilename = Path.Combine(_nasArchive.NasPath, _storageLocation.StudyFolder);
                        commandProcessor.AddCommand(new CreateDirectoryCommand(zipFilename));

                        // Create a folder for the study
                        zipFilename = Path.Combine(zipFilename, _storageLocation.StudyInstanceUid);
                        commandProcessor.AddCommand(new CreateDirectoryCommand(zipFilename));

                        // Save the archive data in the study folder, based on a filename with a date / time stamp
                        string filename = String.Format("{0}.zip", Platform.Time.ToString("yyyy-MM-dd-HHmm"));
                        zipFilename = Path.Combine(zipFilename, filename);


                        // Create the Xml data to store in the ArchiveStudyStorage table telling
                        // where the archived study is located.
                        XmlElement nasArchiveElement = _archiveXml.CreateElement("NasArchive");
                        _archiveXml.AppendChild(nasArchiveElement);
                        XmlElement studyFolderElement = _archiveXml.CreateElement("StudyFolder");
                        nasArchiveElement.AppendChild(studyFolderElement);
                        studyFolderElement.InnerText = _storageLocation.StudyFolder;
                        XmlElement filenameElement = _archiveXml.CreateElement("Filename");
                        nasArchiveElement.AppendChild(filenameElement);
                        filenameElement.InnerText = filename;
                        XmlElement studyInstanceUidElement = _archiveXml.CreateElement("Uid");
                        nasArchiveElement.AppendChild(studyInstanceUidElement);
                        studyInstanceUidElement.InnerText = _storageLocation.StudyInstanceUid;


                        // Create the Zip file
                    	commandProcessor.AddCommand(
                    		new CreateStudyZipCommand(zipFilename, _studyXml, studyFolder, executionContext.TempDirectory));

                        // Update the database.
                        commandProcessor.AddCommand(new InsertArchiveStudyStorageCommand(queueItem.StudyStorageKey, queueItem.PartitionArchiveKey, queueItem.GetKey(), _storageLocation.ServerTransferSyntaxKey, _archiveXml));


                    	StudyRulesEngine studyEngine =
                    		new StudyRulesEngine(_storageLocation, _nasArchive.ServerPartition, _studyXml);
                    	studyEngine.Apply(ServerRuleApplyTimeEnum.StudyArchived, commandProcessor);
						

                        if (!commandProcessor.Execute())
                        {
                            Platform.Log(LogLevel.Error, "Unexpected failure archiving study: {0}", commandProcessor.FailureReason);

                            queueItem.FailureDescription = commandProcessor.FailureReason;
                            _nasArchive.UpdateArchiveQueue(queueItem, ArchiveQueueStatusEnum.Failed, Platform.Time);
                        }
                        else
                            Platform.Log(LogLevel.Info, "Successfully archived study {0} on {1}", _storageLocation.StudyInstanceUid,
                                         _nasArchive.PartitionArchive.Description);

						// Log the current FilesystemQueue settings
						_storageLocation.LogFilesystemQueue();
                    }
                }
                catch (StudyIntegrityValidationFailure ex)
                {
                    StringBuilder error = new StringBuilder();
                    error.AppendLine(String.Format("Partition  : {0}", ex.ValidationStudyInfo.ServerAE));
                    error.AppendLine(String.Format("Patient    : {0}", ex.ValidationStudyInfo.PatientsName));
                    error.AppendLine(String.Format("Study Uid  : {0}", ex.ValidationStudyInfo.StudyInstaneUid));
                    error.AppendLine(String.Format("Accession# : {0}", ex.ValidationStudyInfo.AccessionNumber));
                    error.AppendLine(String.Format("Study Date : {0}", ex.ValidationStudyInfo.StudyDate));

                    queueItem.FailureDescription = error.ToString();
                    _nasArchive.UpdateArchiveQueue(queueItem, ArchiveQueueStatusEnum.Failed, Platform.Time);
                }
                catch (Exception e)
                {
                    String msg = String.Format("Unexpected exception archiving study: {0} on {1}: {2}",
                                 _storageLocation.StudyInstanceUid, _nasArchive.PartitionArchive.Description, e.Message);

                    Platform.Log(LogLevel.Error, e, msg);
                    queueItem.FailureDescription = msg;
                    _nasArchive.UpdateArchiveQueue(queueItem, ArchiveQueueStatusEnum.Failed, Platform.Time);
                }
                finally
                {
                    // Unlock the Queue Entry
                    using (IUpdateContext update = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush))
                    {
                        ILockStudy studyLock = update.GetBroker<ILockStudy>();
                        LockStudyParameters parms = new LockStudyParameters
                                                    	{
                                                    		StudyStorageKey = queueItem.StudyStorageKey,
                                                    		QueueStudyStateEnum = QueueStudyStateEnum.Idle
                                                    	};
                    	bool retVal = studyLock.Execute(parms);
                        if (!parms.Successful || !retVal)
                        {
                            Platform.Log(LogLevel.Info, "Study {0} on partition {1} is failed to unlock.", _storageLocation.StudyInstanceUid, _nasArchive.ServerPartition.Description);
                        }
                        update.Commit();
                    }
                }
            }			
		}
		public void RestoreNearlineStudy(RestoreQueue queueItem, string zipFile, string destinationFolder, string studyFolder)
		{
            ServerFilesystemInfo fs = _nasArchive.Selector.SelectFilesystem();
			if (fs == null)
			{
				DateTime scheduleTime = Platform.Time.AddMinutes(5);
				Platform.Log(LogLevel.Error, "No writeable filesystem for restore, rescheduling restore request to {0}", scheduleTime);
				queueItem.FailureDescription = "No writeable filesystem for restore, rescheduling restore request";
				_nasArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Pending, scheduleTime);
				return;
			}

		    StudyStorageLocation restoredLocation = null;
			try
			{
				using (ServerCommandProcessor processor = 
                    new ServerCommandProcessor("NAS Restore Offline Study"))
				{
					processor.AddCommand(new CreateDirectoryCommand(destinationFolder));
					destinationFolder = Path.Combine(destinationFolder, studyFolder);
					processor.AddCommand(new CreateDirectoryCommand(destinationFolder));
					destinationFolder = Path.Combine(destinationFolder, _studyStorage.StudyInstanceUid);
					processor.AddCommand(new CreateDirectoryCommand(destinationFolder));
					processor.AddCommand(new ExtractZipCommand(zipFile, destinationFolder));

					// We rebuild the StudyXml, in case any settings or issues have happened since archival
					processor.AddCommand(new RebuildStudyXmlCommand(_studyStorage.StudyInstanceUid, destinationFolder));

                    // Apply the rules engine.
					ServerActionContext context =
						new ServerActionContext(null, fs.Filesystem.GetKey(), _nasArchive.ServerPartition,
						                        queueItem.StudyStorageKey) {CommandProcessor = processor};
					processor.AddCommand(
						new ApplyRulesCommand(destinationFolder, _studyStorage.StudyInstanceUid, context));

					// Do the actual insert into the DB
					InsertFilesystemStudyStorageCommand insertStorageCommand = new InsertFilesystemStudyStorageCommand(
													_nasArchive.PartitionArchive.ServerPartitionKey,
						                            _studyStorage.StudyInstanceUid,
						                            studyFolder,
						                            fs.Filesystem.GetKey(), _syntax);
					processor.AddCommand(insertStorageCommand);

					if (!processor.Execute())
					{
						Platform.Log(LogLevel.Error, "Unexpected error processing restore request for {0} on archive {1}",
						             _studyStorage.StudyInstanceUid, _nasArchive.PartitionArchive.Description);
						queueItem.FailureDescription = processor.FailureReason;
						_nasArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Failed, Platform.Time);
					}
					else
					{
					    restoredLocation = insertStorageCommand.Location;

						// Unlock the Queue Entry
						using (
							IUpdateContext update = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush))
						{
							bool retVal = _nasArchive.UpdateRestoreQueue(update, queueItem, RestoreQueueStatusEnum.Completed, Platform.Time.AddSeconds(60));
							ILockStudy studyLock = update.GetBroker<ILockStudy>();
							LockStudyParameters parms = new LockStudyParameters
							                            	{
							                            		StudyStorageKey = queueItem.StudyStorageKey,
							                            		QueueStudyStateEnum = QueueStudyStateEnum.Idle
							                            	};
							retVal = retVal && studyLock.Execute(parms);
							if (!parms.Successful || !retVal)
							{
								string message =
									String.Format("Study {0} on partition {1} failed to unlock.", _studyStorage.StudyInstanceUid,
									              _nasArchive.ServerPartition.Description);
								Platform.Log(LogLevel.Info, message);
								throw new ApplicationException(message);
							}
							update.Commit();

							Platform.Log(LogLevel.Info, "Successfully restored study: {0} on archive {1}", _studyStorage.StudyInstanceUid,
										 _nasArchive.PartitionArchive.Description);

                            OnStudyRestored(restoredLocation);
						}
					}
				}
			}
            catch(StudyIntegrityValidationFailure ex)
            {
                Debug.Assert(restoredLocation != null);
                // study has been restored but it seems corrupted. Need to reprocess it.
                ReprocessStudy(restoredLocation, ex.Message);
            }
			catch (Exception e)
			{
				Platform.Log(LogLevel.Error, e, "Unexpected exception processing restore request for {0} on archive {1}",
							 _studyStorage.StudyInstanceUid, _nasArchive.PartitionArchive.Description);
				_nasArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Failed, Platform.Time);
			}
		}
        private static void OnStudyRestored(StudyStorageLocation location)
        {
            ValidateStudy(location);

            using(ServerCommandProcessor processor = new ServerCommandProcessor("Update Study Size In DB"))
            {
                processor.AddCommand(new UpdateStudySizeInDBCommand(location));
                if (!processor.Execute())
                {
                    Platform.Log(LogLevel.Error, "Unexpected error when trying to update the study size in DB:", processor.FailureReason);
                }
            }
        }
        private void RestoreOnlineStudy(RestoreQueue queueItem, string zipFile, string destinationFolder)
		{
			try
			{
				using (ServerCommandProcessor processor = new ServerCommandProcessor("NAS Restore Online Study"))
				{
					using (ZipFile zip = new ZipFile(zipFile))
					{
						foreach (string file in zip.EntryFileNames)
						{
							processor.AddCommand(new ExtractZipFileAndReplaceCommand(zipFile, file, destinationFolder));
						}
					}

					// We rebuild the StudyXml, in case any settings or issues have happened since archival
					processor.AddCommand(new RebuildStudyXmlCommand(_location.StudyInstanceUid, destinationFolder));

					StudyStatusEnum status;

					if (_syntax.Encapsulated && _syntax.LosslessCompressed)
						status = StudyStatusEnum.OnlineLossless;
					else if (_syntax.Encapsulated && _syntax.LossyCompressed)
						status = StudyStatusEnum.OnlineLossy;
					else
						status = StudyStatusEnum.Online;

					processor.AddCommand(new UpdateStudyStateCommand(_location, status, _serverSyntax));

					// Apply the rules engine.
					ServerActionContext context =
						new ServerActionContext(null, _location.FilesystemKey, _nasArchive.ServerPartition,
												queueItem.StudyStorageKey) {CommandProcessor = processor};
					processor.AddCommand(
						new ApplyRulesCommand(destinationFolder, _location.StudyInstanceUid, context));

					if (!processor.Execute())
					{
						Platform.Log(LogLevel.Error, "Unexpected error processing restore request for {0} on archive {1}",
									 _location.StudyInstanceUid, _nasArchive.PartitionArchive.Description);
						queueItem.FailureDescription = processor.FailureReason;
						_nasArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Failed, Platform.Time);
					}
					else
					{
						// Unlock the Queue Entry and set to complete
						using (IUpdateContext update = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush))
						{
							_nasArchive.UpdateRestoreQueue(update, queueItem, RestoreQueueStatusEnum.Completed, Platform.Time.AddSeconds(60));
							ILockStudy studyLock = update.GetBroker<ILockStudy>();
							LockStudyParameters parms = new LockStudyParameters
							                            	{
							                            		StudyStorageKey = queueItem.StudyStorageKey,
							                            		QueueStudyStateEnum = QueueStudyStateEnum.Idle
							                            	};
							bool retVal = studyLock.Execute(parms);
							if (!parms.Successful || !retVal)
							{
								Platform.Log(LogLevel.Info, "Study {0} on partition {1} failed to unlock.", _location.StudyInstanceUid,
											 _nasArchive.ServerPartition.Description);
							}

							update.Commit();

							Platform.Log(LogLevel.Info, "Successfully restored study: {0} on archive {1}", _location.StudyInstanceUid,
										 _nasArchive.PartitionArchive.Description);

                            OnStudyRestored(_location);
						}
					}
				}
			}
			catch (Exception e)
			{
				Platform.Log(LogLevel.Error, e, "Unexpected exception processing restore request for {0} on archive {1}",
							 _location.StudyInstanceUid, _nasArchive.PartitionArchive.Description);
				queueItem.FailureDescription = e.Message;
				_nasArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Failed, Platform.Time);
			}
		}