protected override int OnStart(StudyLoaderArgs studyLoaderArgs) { _sops = null; EventResult result = EventResult.Success; var loadedInstances = new AuditedInstances(); try { using (var context = new DataAccessContext()) { IStudy study = context.GetStudyBroker().GetStudy(studyLoaderArgs.StudyInstanceUid); if (study == null) { result = EventResult.MajorFailure; loadedInstances.AddInstance(studyLoaderArgs.StudyInstanceUid); throw new NotFoundLoadStudyException(studyLoaderArgs.StudyInstanceUid); } loadedInstances.AddInstance(study.PatientId, study.PatientsName, study.StudyInstanceUid); _sops = study.GetSopInstances().GetEnumerator(); return study.NumberOfStudyRelatedInstances; } } finally { AuditHelper.LogOpenStudies(new[] { AuditHelper.LocalAETitle }, loadedInstances, EventSource.CurrentUser, result); } }
private bool Initialize() { _synchronizationContext = SynchronizationContext.Current; _exportedInstances = new AuditedInstances(); _canceled = false; _overwrite = false; if (Anonymize) { ExportComponent component = new ExportComponent(); component.OutputPath = OutputPath; if (DialogBoxAction.Ok != DesktopWindow.ShowDialogBox(component, SR.Export)) return false; OutputPath = component.OutputPath; StudyData studyData = new StudyData { PatientId = component.PatientId, PatientsNameRaw = component.PatientsName, PatientsBirthDate = component.PatientsDateOfBirth, StudyId = component.StudyId, StudyDescription = component.StudyDescription, AccessionNumber = component.AccessionNumber, StudyDate = component.StudyDate }; _anonymizer = new DicomAnonymizer(); _anonymizer.ValidationOptions = ValidationOptions.RelaxAllChecks; _anonymizer.StudyDataPrototype = studyData; } else { SelectFolderDialogCreationArgs args = new SelectFolderDialogCreationArgs(); args.Prompt = SR.MessageSelectOutputLocation; args.Path = OutputPath; FileDialogResult result = DesktopWindow.ShowSelectFolderDialogBox(args); if (result.Action != DialogBoxAction.Ok) return false; OutputPath = result.FileName; } return true; }
protected override int OnStart(StudyLoaderArgs studyLoaderArgs) { var ae = studyLoaderArgs.Server as IDicomServiceNode; _ae = ae; EventResult result = EventResult.Success; AuditedInstances loadedInstances = new AuditedInstances(); try { ServerPartition partition = ServerPartitionMonitor.Instance.GetPartition(_ae.AETitle); if (!partition.Enabled) throw new OfflineLoadStudyException(studyLoaderArgs.StudyInstanceUid); FilesystemMonitor.Instance.GetReadableStudyStorageLocation(partition.Key, studyLoaderArgs.StudyInstanceUid, StudyRestore.False, StudyCache.True, out _location); StudyXml studyXml = _location.LoadStudyXml(); _instances = GetInstances(studyXml).GetEnumerator(); loadedInstances.AddInstance(studyXml.PatientId, studyXml.PatientsName, studyXml.StudyInstanceUid); return studyXml.NumberOfStudyRelatedInstances; } catch (StudyIsNearlineException e) { throw new NearlineLoadStudyException(studyLoaderArgs.StudyInstanceUid, e); } finally { AuditHelper.LogOpenStudies(new[] {ae.AETitle}, loadedInstances, EventSource.CurrentUser, result); } }
public void RetrieveStudy(IDicomServiceNode remoteAEInfo, IStudyRootData study) { EventResult result = EventResult.Success; try { var request = new DicomRetrieveStudyRequest { ServerName = remoteAEInfo.Name, Study = new WorkItemStudy(study), Patient = new WorkItemPatient(study) }; // TODO (CR Jul 2012): The service itself has logic like this already, so this should probably be there, too. // Then, we could also get rid of this GetMatching... method. var data = GetMatchingActiveWorkItem(request); if (data != null) { var existingRequest = data.Request as DicomRetrieveStudyRequest; if (existingRequest != null && remoteAEInfo.Name == existingRequest.ServerName) { Request = data.Request; return; } } InsertRequest(request, new DicomRetrieveProgress()); } catch (Exception ex) { result = EventResult.MajorFailure; Exception = ex; Platform.Log(LogLevel.Error, ex, Common.SR.MessageFailedToSendStudy); throw; } finally { var instances = new AuditedInstances(); instances.AddInstance(study.PatientId, study.PatientsName, study.StudyInstanceUid); AuditHelper.LogBeginReceiveInstances(remoteAEInfo.AETitle, remoteAEInfo.ScpParameters.HostName, instances, string.IsNullOrEmpty(Request.UserName) ? EventSource.CurrentProcess : EventSource.CurrentUser, result); } }
public void PublishFiles(IDicomServiceNode remoteAEInfo, IStudyRootData study, DeletionBehaviour behaviour, List<string> files) { EventResult result = EventResult.Success; try { var request = new PublishFilesRequest { DestinationServerName = remoteAEInfo.Name, Priority = WorkItemPriorityEnum.High, DeletionBehaviour = behaviour, Study = new WorkItemStudy(study), Patient = new WorkItemPatient(study), FilePaths = files }; InsertRequest(request, new DicomSendProgress()); } catch (Exception ex) { result = EventResult.MajorFailure; Exception = ex; Platform.Log(LogLevel.Error, ex, Common.SR.MessageFailedToSendSops); throw; } finally { var instances = new AuditedInstances(); instances.AddInstance(study.PatientId, study.PatientsName, study.StudyInstanceUid); AuditHelper.LogBeginSendInstances(remoteAEInfo.AETitle, remoteAEInfo.ScpParameters.HostName, instances, string.IsNullOrEmpty(Request.UserName) ? EventSource.CurrentProcess : EventSource.CurrentUser, result); } }
public void SendSops(IDicomServiceNode remoteAEInfo, IStudyRootData study, string seriesInstanceUid, string[] sopInstanceUids, WorkItemPriorityEnum priority) { EventResult result = EventResult.Success; try { var request = new DicomSendSopRequest { DestinationServerName = remoteAEInfo.Name, SeriesInstanceUid = seriesInstanceUid, SopInstanceUids = new List<string>(), Priority = priority, Study = new WorkItemStudy(study), Patient = new WorkItemPatient(study) }; request.SopInstanceUids.AddRange(sopInstanceUids); InsertRequest(request, new DicomSendProgress()); } catch (Exception ex) { result = EventResult.MajorFailure; Exception = ex; Platform.Log(LogLevel.Error, ex, Common.SR.MessageFailedToSendSops); throw; } finally { var instances = new AuditedInstances(); instances.AddInstance(study.PatientId, study.PatientsName, study.StudyInstanceUid); AuditHelper.LogBeginSendInstances(remoteAEInfo.AETitle, remoteAEInfo.ScpParameters.HostName, instances, string.IsNullOrEmpty(Request.UserName) ? EventSource.CurrentProcess : EventSource.CurrentUser, result); } }
public void DeleteSeries(IStudyRootData study, List<string> seriesInstanceUids) { EventResult result = EventResult.Success; try { var request = new DeleteSeriesRequest { Study = new WorkItemStudy(study), Patient = new WorkItemPatient(study), SeriesInstanceUids = seriesInstanceUids }; InsertRequest(request, new DeleteProgress()); } catch (Exception ex) { result = EventResult.MajorFailure; Exception = ex; throw; } finally { var instances = new AuditedInstances(); instances.AddInstance(study.PatientId, study.PatientsName, study.StudyInstanceUid); AuditHelper.LogDeleteSeries(new List<string> {AuditHelper.LocalAETitle}, instances, EventSource.CurrentUser, result); } }
/// <summary> /// Generates a "Dicom Instances Accessed" update event in the audit log (with ActionCode of Delete), according to DICOM Supplement 95. /// </summary> /// <remarks> /// This method automatically separates different patients into separately logged events, as required by DICOM. /// /// We chose to impleemnt the DicomInstancesAccessed audit log, as opposed to the DicomStudyDeleted audit message because the whole /// study isn't being deleted, just a series. /// </remarks> /// <param name="aeTitles">The application entities from which the instances were accessed.</param> /// <param name="instances">The studies that the series belong that are being deleted.</param> /// <param name="eventSource">The source user or application entity which invoked the operation.</param> /// <param name="eventResult">The result of the operation.</param> public static void LogDeleteSeries(IEnumerable <string> aeTitles, AuditedInstances instances, EventSource eventSource, EventResult eventResult) { AuditLogHelper.LogDeleteSeries(aeTitles, instances, eventSource, eventResult); }
protected void LoadImportContext(ServerAssociationParameters association) { _importContext = new DicomReceiveImportContext(association.CallingAE, GetRemoteHostName(association), StudyStore.GetConfiguration(), EventSource.CurrentProcess); // Publish new WorkItems as they're added to the context lock (_importContext.StudyWorkItemsSyncLock) { _importContext.StudyWorkItems.ItemAdded += delegate(object sender, DictionaryEventArgs<string, WorkItem> args) { Platform.GetService( (IWorkItemActivityMonitorService service) => service.Publish(new WorkItemPublishRequest { Item = WorkItemDataHelper.FromWorkItem(args.Item) })); var auditedInstances = new AuditedInstances(); var request = args.Item.Request as DicomReceiveRequest; if (request != null) { auditedInstances.AddInstance(request.Patient.PatientId, request.Patient.PatientsName, request.Study.StudyInstanceUid); } AuditHelper.LogReceivedInstances( association.CallingAE, GetRemoteHostName(association), auditedInstances, EventSource.CurrentProcess, EventResult.Success, EventReceiptAction.ActionUnknown); }; _importContext.StudyWorkItems.ItemChanged += (sender, args) => Platform.GetService( (IWorkItemActivityMonitorService service) => service.Publish(new WorkItemPublishRequest { Item = WorkItemDataHelper.FromWorkItem(args.Item) })); } }
protected void LoadImportContext(ServerAssociationParameters association) { _importContext = new DicomReceiveImportContext(association.CallingAE, GetRemoteHostName(association), StudyStore.GetConfiguration(), EventSource.CurrentProcess); // Publish new WorkItems as they're added to the context lock (_importContext.StudyWorkItemsSyncLock) { _importContext.StudyWorkItems.ItemAdded += (sender, args) => { _importContext.PublishWorkItemActivity(WorkItemDataHelper.FromWorkItem(args.Item)); var auditedInstances = new AuditedInstances(); var request = args.Item.Request as DicomReceiveRequest; if (request != null) auditedInstances.AddInstance(request.Patient.PatientId, request.Patient.PatientsName, request.Study.StudyInstanceUid); AuditHelper.LogReceivedInstances( association.CallingAE, GetRemoteHostName(association), auditedInstances, EventSource.CurrentProcess, EventResult.Success, EventReceiptAction.ActionUnknown); }; _importContext.StudyWorkItems.ItemChanged += (sender, args) => _importContext.PublishWorkItemActivity(WorkItemDataHelper.FromWorkItem(args.Item)); } }
/// <summary> /// Generates a "DICOM Instances Transferred" received event in the audit log, according to DICOM Supplement 95. /// </summary> /// <remarks> /// This method automatically separates different patients into separately logged events, as required by DICOM. /// </remarks> /// <param name="remoteAETitle">The application entity from which the transfer was completed.</param> /// <param name="remoteHostName">The hostname of the application entity from which the transfer was completed.</param> /// <param name="instances">The studies that were transferred.</param> /// <param name="eventSource">The source user or application entity which invoked the operation.</param> /// <param name="eventResult">The result of the operation.</param> /// <param name="action">The action taken on the studies that were transferred.</param> public static void LogReceivedInstances(string remoteAETitle, string remoteHostName, AuditedInstances instances, EventSource eventSource, EventResult eventResult, EventReceiptAction action) { AuditLogHelper.LogReceivedInstances(LocalAETitle, remoteAETitle, remoteHostName, instances, eventSource, eventResult, action); }
/// <summary> /// Generates a "Begin Transferring DICOM Instances" receive event in the audit log, according to DICOM Supplement 95. /// </summary> /// <remarks> /// This method automatically separates different patients into separately logged events, as required by DICOM. /// </remarks> /// <param name="remoteAETitle">The application entity from which the transfer was started.</param> /// <param name="remoteHostName">The hostname of the application entity from which the transfer was started.</param> /// <param name="instances">The studies that were requested for transfer.</param> /// <param name="eventSource">The source user or application entity which invoked the operation.</param> /// <param name="eventResult">The result of the operation.</param> public static void LogBeginReceiveInstances(string remoteAETitle, string remoteHostName, AuditedInstances instances, EventSource eventSource, EventResult eventResult) { AuditLogHelper.LogBeginReceiveInstances(LocalAETitle, remoteAETitle, remoteHostName, instances, eventSource, eventResult); }
protected override int OnStart(StudyLoaderArgs studyLoaderArgs) { var serverAe = studyLoaderArgs.Server; Platform.CheckForNullReference(serverAe, "Server"); Platform.CheckMemberIsSet(serverAe.StreamingParameters, "StreamingParameters"); _serverAe = serverAe; EventResult result = EventResult.Success; AuditedInstances loadedInstances = new AuditedInstances(); try { StudyXml studyXml = RetrieveStudyXml(studyLoaderArgs); _instances = GetInstances(studyXml).GetEnumerator(); loadedInstances.AddInstance(studyXml.PatientId, studyXml.PatientsName, studyXml.StudyInstanceUid); return studyXml.NumberOfStudyRelatedInstances; } finally { AuditHelper.LogOpenStudies(new string[] { _serverAe.AETitle }, loadedInstances, EventSource.CurrentUser, result); } }
private void AuditSendOperation(bool noExceptions) { if (noExceptions) { var sentInstances = new AuditedInstances(); var failedInstances = new AuditedInstances(); foreach (StorageInstance instance in StorageInstanceList) { if (instance.SendStatus.Status == DicomState.Success) sentInstances.AddInstance(instance.PatientId, instance.PatientsName, instance.StudyInstanceUid); else failedInstances.AddInstance(instance.PatientId, instance.PatientsName, instance.StudyInstanceUid); } AuditHelper.LogSentInstances(RemoteAE, RemoteHost, sentInstances, EventSource.CurrentProcess, EventResult.Success); AuditHelper.LogSentInstances(RemoteAE, RemoteHost, failedInstances, EventSource.CurrentProcess, EventResult.MinorFailure); } else { var sentInstances = new AuditedInstances(); foreach (StorageInstance instance in StorageInstanceList) sentInstances.AddInstance(instance.PatientId, instance.PatientsName, instance.StudyInstanceUid); AuditHelper.LogSentInstances(RemoteAE, RemoteHost, sentInstances, EventSource.CurrentProcess, EventResult.MajorFailure); } }
public override bool OnReceiveRequest(ClearCanvas.Dicom.Network.DicomServer server, ServerAssociationParameters association, byte presentationID, DicomMessage message) { string studyInstanceUid; string seriesInstanceUid; DicomUid sopInstanceUid; bool ok = message.DataSet[DicomTags.SopInstanceUid].TryGetUid(0, out sopInstanceUid); if (ok) ok = message.DataSet[DicomTags.SeriesInstanceUid].TryGetString(0, out seriesInstanceUid); if (ok) ok = message.DataSet[DicomTags.StudyInstanceUid].TryGetString(0, out studyInstanceUid); if (!ok) { Platform.Log(LogLevel.Error, "Unable to retrieve UIDs from request message, sending failure status."); server.SendCStoreResponse(presentationID, message.MessageId, sopInstanceUid.UID, DicomStatuses.ProcessingFailure); return true; } if (_importContext == null) { _importContext = new DicomReceiveImportContext(association.CallingAE, GetRemoteHostName(association), StudyStore.GetConfiguration(), EventSource.CurrentProcess); // Publish new WorkItems as they're added to the context lock (_importContext.StudyWorkItemsSyncLock) { _importContext.StudyWorkItems.ItemAdded += delegate(object sender, DictionaryEventArgs<string,WorkItem> args) { Platform.GetService( (IWorkItemActivityMonitorService service) => service.Publish(new WorkItemPublishRequest { Item = WorkItemDataHelper .FromWorkItem( args.Item) })); var auditedInstances = new AuditedInstances(); var request = args.Item.Request as DicomReceiveRequest; if (request != null) { auditedInstances.AddInstance(request.Patient.PatientId, request.Patient.PatientsName, request.Study.StudyInstanceUid); } AuditHelper.LogReceivedInstances( association.CallingAE, GetRemoteHostName(association), auditedInstances, EventSource.CurrentProcess, EventResult.Success, EventReceiptAction.ActionUnknown); } ; _importContext.StudyWorkItems.ItemChanged += (sender, args) => Platform.GetService( (IWorkItemActivityMonitorService service) => service.Publish(new WorkItemPublishRequest {Item = WorkItemDataHelper.FromWorkItem(args.Item)})); } } var importer = new ImportFilesUtility(_importContext); var result = importer.Import(message,BadFileBehaviourEnum.Ignore, FileImportBehaviourEnum.Save); 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, association.CallingAE, association.CalledAE, result.AccessionNumber, result.StudyInstanceUid); else Platform.Log(LogLevel.Info, "Received SOP Instance {0} from {1} to {2} (StudyUid:{3})", result.SopInstanceUid, association.CallingAE, association.CalledAE, result.StudyInstanceUid); server.SendCStoreResponse(presentationID, message.MessageId, message.AffectedSopInstanceUid, result.DicomStatus); } else { if (result.DicomStatus==DicomStatuses.ProcessingFailure) Platform.Log(LogLevel.Error, "Failure importing sop: {0}", result.ErrorMessage); //OnReceiveError(message, result.ErrorMessage, association.CallingAE); server.SendCStoreResponse(presentationID, message.MessageId, message.AffectedSopInstanceUid, result.DicomStatus, result.ErrorMessage); } return true; }
public void RetrieveSeries(IDicomServiceNode remoteAEInfo, IStudyRootData study, string[] seriesInstanceUids) { EventResult result = EventResult.Success; try { var request = new DicomRetrieveSeriesRequest { ServerName = remoteAEInfo.Name, SeriesInstanceUids = new List<string>(), Study = new WorkItemStudy(study), Patient = new WorkItemPatient(study) }; request.SeriesInstanceUids.AddRange(seriesInstanceUids); InsertRequest(request, new DicomRetrieveProgress()); } catch (Exception ex) { result = EventResult.MajorFailure; Exception = ex; throw; } finally { var instances = new AuditedInstances(); instances.AddInstance(study.PatientId, study.PatientsName, study.StudyInstanceUid); AuditHelper.LogBeginReceiveInstances(remoteAEInfo.AETitle, remoteAEInfo.ScpParameters.HostName, instances, string.IsNullOrEmpty(Request.UserName) ? EventSource.CurrentProcess : EventSource.CurrentUser, result); } }
/// <summary> /// Generates a "Data Export" event in the audit log, according to DICOM Supplement 95. /// </summary> /// <remarks> /// One audit event is generated for each file system volume to which data is exported. /// If the audited instances are not on a file system, a single event is generated with an empty media identifier. /// </remarks> /// <param name="instances">The files that were exported.</param> /// <param name="eventSource">The source user or application entity which invoked the operation.</param> /// <param name="eventResult">The result of the operation.</param> public static void LogExportStudies(AuditedInstances instances, EventSource eventSource, EventResult eventResult) { AuditLogHelper.LogExportStudies(instances, eventSource, EventSource.GetCurrentDicomAE(), eventResult); }
/// <summary> /// Generates a "Dicom Study Deleted" event in the audit log, according to DICOM Supplement 95. /// </summary> /// <remarks> /// This method automatically separates different patients into separately logged events, as required by DICOM. /// </remarks> /// <param name="aeTitle">The application entity from which the instances were deleted.</param> /// <param name="instances">The studies that were deleted.</param> /// <param name="eventSource">The source user or application entity which invoked the operation.</param> /// <param name="eventResult">The result of the operation.</param> public static void LogDeleteStudies(string aeTitle, AuditedInstances instances, EventSource eventSource, EventResult eventResult) { AuditLogHelper.LogDeleteStudies(aeTitle, instances, eventSource, eventResult); }
private void Anonymize(IBackgroundTaskContext context) { //TODO (Marmot) This probably should be its own WorkItem type and have it done in the background there. var study = (StudyTableItem) context.UserState; var anonymizedInstances = new AuditedInstances(); try { context.ReportProgress(new BackgroundTaskProgress(0, SR.MessageAnonymizingStudy)); var loader = study.Server.GetService<IStudyLoader>(); int numberOfSops = loader.Start(new StudyLoaderArgs(study.StudyInstanceUid, null)); if (numberOfSops <= 0) return; var anonymizer = new DicomAnonymizer {StudyDataPrototype = _component.AnonymizedData}; if (_component.PreserveSeriesData) { //The default anonymizer removes the series data, so we just clone the original. anonymizer.AnonymizeSeriesDataDelegate = original => original.Clone(); } // Setup the ImportFilesUtility to perform the import var configuration = DicomServer.GetConfiguration(); // setup auditing information var result = EventResult.Success; string patientsSex = null; for (int i = 0; i < numberOfSops; ++i) { using (var sop = loader.LoadNextSop()) { if (sop != null && (_component.KeepReportsAndAttachments || !IsReportOrAttachmentSopClass(sop.SopClassUid))) { //preserve the patient sex. if (patientsSex == null) anonymizer.StudyDataPrototype.PatientsSex = patientsSex = sop.PatientsSex ?? ""; var localSopDataSource = sop.DataSource as ILocalSopDataSource; if (localSopDataSource != null) { string filename = string.Format("{0}.dcm", i); DicomFile file = (localSopDataSource).File; // make sure we anonymize a new instance, not the same instance that the Sop cache holds!! file = new DicomFile(filename, file.MetaInfo.Copy(), file.DataSet.Copy()); anonymizer.Anonymize(file); // TODO (CR Jun 2012): Importing each file separately? Platform.GetService((IPublishFiles w) => w.PublishLocal(new List<DicomFile> {file})); string studyInstanceUid = file.DataSet[DicomTags.StudyInstanceUid].ToString(); string patientId = file.DataSet[DicomTags.PatientId].ToString(); string patientsName = file.DataSet[DicomTags.PatientsName].ToString(); anonymizedInstances.AddInstance(patientId, patientsName, studyInstanceUid); var progressPercent = (int)Math.Floor((i + 1) / (float)numberOfSops * 100); var progressMessage = String.Format(SR.MessageAnonymizingStudy, file.MediaStorageSopInstanceUid); context.ReportProgress(new BackgroundTaskProgress(progressPercent, progressMessage)); } } } } AuditHelper.LogCreateInstances(new[]{configuration.AETitle}, anonymizedInstances, EventSource.CurrentUser, result); context.Complete(); } catch (Exception e) { AuditHelper.LogCreateInstances(new[] { string.Empty }, anonymizedInstances, EventSource.CurrentUser, EventResult.MajorFailure); context.Error(e); } }
protected override int OnStart(StudyLoaderArgs studyLoaderArgs) { _sops = null; EventResult result = EventResult.Success; var loadedInstances = new AuditedInstances(); try { using (var context = new DataAccessContext()) { if (!studyLoaderArgs.Options.IgnoreInUse) { var activeUpdateItems = context.GetWorkItemBroker().GetWorkItems(WorkItemConcurrency.StudyUpdate, WorkItemStatusFilter.Active, studyLoaderArgs.StudyInstanceUid); var activeDeleteItems = context.GetWorkItemBroker().GetWorkItems(WorkItemConcurrency.StudyDelete, WorkItemStatusFilter.Active, studyLoaderArgs.StudyInstanceUid); if (activeUpdateItems.Any() || activeDeleteItems.Any()) { var message = string.Format("There are work items actively modifying the study with UID '{0}'.", studyLoaderArgs.StudyInstanceUid); throw new InUseLoadStudyException(studyLoaderArgs.StudyInstanceUid, message); } } IStudy study = context.GetStudyBroker().GetStudy(studyLoaderArgs.StudyInstanceUid); if (study == null) { result = EventResult.MajorFailure; loadedInstances.AddInstance(studyLoaderArgs.StudyInstanceUid); throw new NotFoundLoadStudyException(studyLoaderArgs.StudyInstanceUid); } loadedInstances.AddInstance(study.PatientId, study.PatientsName, study.StudyInstanceUid); _sops = study.GetSopInstances().GetEnumerator(); return study.NumberOfStudyRelatedInstances; } } finally { AuditHelper.LogOpenStudies(new[] { AuditHelper.LocalAETitle }, loadedInstances, EventSource.CurrentUser, result); } }