# HG changeset patch # User Sebastien Jodogne # Date 1356106684 -3600 # Node ID fc856d175d18fd883147f244909e2aa7e08165c3 # Parent 4f17834a50b61a58264c11ea681d26c997140fc8 modifications diff -r 4f17834a50b6 -r fc856d175d18 Core/DicomFormat/DicomInstanceHasher.cpp --- a/Core/DicomFormat/DicomInstanceHasher.cpp Fri Dec 21 13:53:24 2012 +0100 +++ b/Core/DicomFormat/DicomInstanceHasher.cpp Fri Dec 21 17:18:04 2012 +0100 @@ -36,12 +36,15 @@ namespace Orthanc { - DicomInstanceHasher::DicomInstanceHasher(const DicomMap& instance) + void DicomInstanceHasher::Setup(const std::string& patientId, + const std::string& studyUid, + const std::string& seriesUid, + const std::string& instanceUid) { - patientId_ = instance.GetValue(DICOM_TAG_PATIENT_ID).AsString(); - studyUid_ = instance.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).AsString(); - seriesUid_ = instance.GetValue(DICOM_TAG_SERIES_INSTANCE_UID).AsString(); - instanceUid_ = instance.GetValue(DICOM_TAG_SOP_INSTANCE_UID).AsString(); + patientId_ = patientId; + studyUid_ = studyUid; + seriesUid_ = seriesUid; + instanceUid_ = instanceUid; if (patientId_.size() == 0 || studyUid_.size() == 0 || @@ -52,6 +55,14 @@ } } + DicomInstanceHasher::DicomInstanceHasher(const DicomMap& instance) + { + Setup(instance.GetValue(DICOM_TAG_PATIENT_ID).AsString(), + instance.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).AsString(), + instance.GetValue(DICOM_TAG_SERIES_INSTANCE_UID).AsString(), + instance.GetValue(DICOM_TAG_SOP_INSTANCE_UID).AsString()); + } + const std::string& DicomInstanceHasher::HashPatient() { if (patientHash_.size() == 0) diff -r 4f17834a50b6 -r fc856d175d18 Core/DicomFormat/DicomInstanceHasher.h --- a/Core/DicomFormat/DicomInstanceHasher.h Fri Dec 21 13:53:24 2012 +0100 +++ b/Core/DicomFormat/DicomInstanceHasher.h Fri Dec 21 17:18:04 2012 +0100 @@ -59,9 +59,22 @@ std::string seriesHash_; std::string instanceHash_; + void Setup(const std::string& patientId, + const std::string& studyUid, + const std::string& seriesUid, + const std::string& instanceUid); + public: DicomInstanceHasher(const DicomMap& instance); + DicomInstanceHasher(const std::string& patientId, + const std::string& studyUid, + const std::string& seriesUid, + const std::string& instanceUid) + { + Setup(patientId, studyUid, seriesUid, instanceUid); + } + const std::string& GetPatientId() const { return patientId_; diff -r 4f17834a50b6 -r fc856d175d18 OrthancServer/FromDcmtkBridge.cpp --- a/OrthancServer/FromDcmtkBridge.cpp Fri Dec 21 13:53:24 2012 +0100 +++ b/OrthancServer/FromDcmtkBridge.cpp Fri Dec 21 17:18:04 2012 +0100 @@ -690,6 +690,23 @@ } + + DicomInstanceHasher ParsedDicomFile::GetHasher() + { + std::string patientId, studyUid, seriesUid, instanceUid; + + if (!GetTagValue(patientId, DICOM_TAG_PATIENT_ID) || + !GetTagValue(studyUid, DICOM_TAG_STUDY_INSTANCE_UID) || + !GetTagValue(seriesUid, DICOM_TAG_SERIES_INSTANCE_UID) || + !GetTagValue(instanceUid, DICOM_TAG_SOP_INSTANCE_UID)) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + + return DicomInstanceHasher(patientId, studyUid, seriesUid, instanceUid); + } + + void FromDcmtkBridge::Convert(DicomMap& target, DcmDataset& dataset) { target.Clear(); diff -r 4f17834a50b6 -r fc856d175d18 OrthancServer/FromDcmtkBridge.h --- a/OrthancServer/FromDcmtkBridge.h Fri Dec 21 13:53:24 2012 +0100 +++ b/OrthancServer/FromDcmtkBridge.h Fri Dec 21 17:18:04 2012 +0100 @@ -32,7 +32,7 @@ #pragma once -#include "../Core/DicomFormat/DicomMap.h" +#include "../Core/DicomFormat/DicomInstanceHasher.h" #include "../Core/RestApi/RestApiOutput.h" #include "../Core/Toolbox.h" @@ -121,6 +121,8 @@ bool GetTagValue(std::string& value, const DicomTag& tag); + + DicomInstanceHasher GetHasher(); }; class FromDcmtkBridge diff -r 4f17834a50b6 -r fc856d175d18 OrthancServer/OrthancRestApi.cpp --- a/OrthancServer/OrthancRestApi.cpp Fri Dec 21 13:53:24 2012 +0100 +++ b/OrthancServer/OrthancRestApi.cpp Fri Dec 21 17:18:04 2012 +0100 @@ -59,6 +59,10 @@ namespace Orthanc { + // TODO IMPROVE MULTITHREADING + static boost::mutex cacheMutex_; + + // DICOM SCU ---------------------------------------------------------------- static void ConnectToModality(DicomUserConnection& connection, @@ -827,9 +831,7 @@ static void GetRawContent(RestApi::GetCall& call) { - // TODO IMPROVE MULTITHREADING - static boost::mutex mutex_; - boost::mutex::scoped_lock lock(mutex_); + boost::mutex::scoped_lock lock(cacheMutex_); RETRIEVE_CONTEXT(call); std::string id = call.GetUriComponent("id", ""); @@ -1098,6 +1100,8 @@ bool removePrivateTags, RestApi::PostCall& call) { + boost::mutex::scoped_lock lock(cacheMutex_); + RETRIEVE_CONTEXT(call); std::string id = call.GetUriComponent("id", ""); @@ -1154,31 +1158,33 @@ { RETRIEVE_CONTEXT(call); - typedef std::list Instances; - Instances instances; - std::string id = call.GetUriComponent("id", ""); - context.GetIndex().GetChildInstances(instances, id); - - if (instances.size() == 0) - { - return; - } - Removals removals; Replacements replacements; bool removePrivateTags; if (ParseModifyRequest(removals, replacements, removePrivateTags, call)) { - std::string newSeriesId; + boost::mutex::scoped_lock lock(cacheMutex_); + + typedef std::list Instances; + Instances instances; + std::string id = call.GetUriComponent("id", ""); + context.GetIndex().GetChildInstances(instances, id); + + if (instances.size() == 0) + { + return; + } + replacements[DICOM_TAG_SERIES_INSTANCE_UID] = FromDcmtkBridge::GenerateUniqueIdentifier(DicomRootLevel_Series); + std::string newSeriesId; for (Instances::const_iterator it = instances.begin(); it != instances.end(); it++) { LOG(INFO) << "Modifying instance " << *it; - ParsedDicomFile& dicom = context.GetDicomFile(*it); - std::auto_ptr modified(dicom.Clone()); + ParsedDicomFile& original = context.GetDicomFile(*it); + std::auto_ptr modified(original.Clone()); ReplaceInstanceInternal(*modified, removals, replacements, DicomReplaceMode_InsertIfAbsent, removePrivateTags); std::string modifiedInstance; @@ -1188,16 +1194,23 @@ return; } - if (newSeriesId.size() == 0 && - !context.GetIndex().LookupParent(newSeriesId, modifiedInstance)) + DicomInstanceHasher modifiedHasher = modified->GetHasher(); + DicomInstanceHasher originalHasher = original.GetHasher(); + + if (newSeriesId.size() == 0) { - throw OrthancException(ErrorCode_InternalError); + assert(id == originalHasher.HashSeries()); + newSeriesId = modifiedHasher.HashSeries(); + context.GetIndex().SetMetadata(newSeriesId, MetadataType_ModifiedFrom, id); } - // TODO for the instances and the series: - // context.GetIndex().SetMetadata(id, MetadataType_ModifiedFrom, id); + assert(*it == originalHasher.HashInstance()); + assert(modifiedInstance == modifiedHasher.HashInstance()); + context.GetIndex().SetMetadata(modifiedInstance, MetadataType_ModifiedFrom, *it); } + context.GetIndex().LogChange(ChangeType_ModifiedSeries, newSeriesId); + assert(newSeriesId.size() != 0); Json::Value result = Json::objectValue; result["ID"] = newSeriesId; @@ -1214,15 +1227,6 @@ typedef std::list Instances; typedef std::map SeriesUidMap; - Instances instances; - std::string id = call.GetUriComponent("id", ""); - context.GetIndex().GetChildInstances(instances, id); - - if (instances.size() == 0) - { - return; - } - SeriesUidMap seriesUidMap; Removals removals; Replacements replacements; @@ -1230,6 +1234,17 @@ if (ParseModifyRequest(removals, replacements, removePrivateTags, call)) { + boost::mutex::scoped_lock lock(cacheMutex_); + + Instances instances; + std::string id = call.GetUriComponent("id", ""); + context.GetIndex().GetChildInstances(instances, id); + + if (instances.size() == 0) + { + return; + } + std::string newStudyId; replacements[DICOM_TAG_STUDY_INSTANCE_UID] = FromDcmtkBridge::GenerateUniqueIdentifier(DicomRootLevel_Study); @@ -1237,27 +1252,30 @@ it != instances.end(); it++) { LOG(INFO) << "Modifying instance " << *it; - ParsedDicomFile& dicom = context.GetDicomFile(*it); + ParsedDicomFile& original = context.GetDicomFile(*it); - std::string seriesId; - if (!dicom.GetTagValue(seriesId, DICOM_TAG_SERIES_INSTANCE_UID)) + std::string seriesUid; + if (!original.GetTagValue(seriesUid, DICOM_TAG_SERIES_INSTANCE_UID)) { throw OrthancException(ErrorCode_InternalError); } - SeriesUidMap::const_iterator it2 = seriesUidMap.find(seriesId); + bool isNewSeries; + SeriesUidMap::const_iterator it2 = seriesUidMap.find(seriesUid); if (it2 == seriesUidMap.end()) { std::string newSeriesUid = FromDcmtkBridge::GenerateUniqueIdentifier(DicomRootLevel_Series); - seriesUidMap[seriesId] = newSeriesUid; + seriesUidMap[seriesUid] = newSeriesUid; replacements[DICOM_TAG_SERIES_INSTANCE_UID] = newSeriesUid; + isNewSeries = true; } else { replacements[DICOM_TAG_SERIES_INSTANCE_UID] = it2->second; + isNewSeries = false; } - std::auto_ptr modified(dicom.Clone()); + std::auto_ptr modified(original.Clone()); ReplaceInstanceInternal(*modified, removals, replacements, DicomReplaceMode_InsertIfAbsent, removePrivateTags); std::string modifiedInstance; @@ -1267,20 +1285,28 @@ return; } + DicomInstanceHasher modifiedHasher = modified->GetHasher(); + DicomInstanceHasher originalHasher = original.GetHasher(); + + if (isNewSeries) + { + context.GetIndex().SetMetadata + (modifiedHasher.HashSeries(), MetadataType_ModifiedFrom, originalHasher.HashSeries()); + } + if (newStudyId.size() == 0) { - // TODO FOR instances, studies and series: - // context.GetIndex().SetMetadata(id, MetadataType_ModifiedFrom, id); + newStudyId = modifiedHasher.HashStudy(); + context.GetIndex().SetMetadata(newStudyId, MetadataType_ModifiedFrom, originalHasher.HashStudy()); + } - std::string newSeriesId; - if (!context.GetIndex().LookupParent(newSeriesId, modifiedInstance) || - !context.GetIndex().LookupParent(newStudyId, newSeriesId)) - { - throw OrthancException(ErrorCode_InternalError); - } - } + assert(*it == originalHasher.HashInstance()); + assert(modifiedInstance == modifiedHasher.HashInstance()); + context.GetIndex().SetMetadata(modifiedInstance, MetadataType_ModifiedFrom, *it); } + context.GetIndex().LogChange(ChangeType_ModifiedStudy, newStudyId); + assert(newStudyId.size() != 0); Json::Value result = Json::objectValue; result["ID"] = newStudyId; diff -r 4f17834a50b6 -r fc856d175d18 OrthancServer/ServerEnumerations.cpp --- a/OrthancServer/ServerEnumerations.cpp Fri Dec 21 13:53:24 2012 +0100 +++ b/OrthancServer/ServerEnumerations.cpp Fri Dec 21 17:18:04 2012 +0100 @@ -137,6 +137,18 @@ case ChangeType_NewStudy: return "NewStudy"; + case ChangeType_AnonymizedStudy: + return "AnonymizedStudy"; + + case ChangeType_AnonymizedSeries: + return "AnonymizedSeries"; + + case ChangeType_ModifiedStudy: + return "ModifiedStudy"; + + case ChangeType_ModifiedSeries: + return "ModifiedSeries"; + default: throw OrthancException(ErrorCode_ParameterOutOfRange); } diff -r 4f17834a50b6 -r fc856d175d18 OrthancServer/ServerEnumerations.h --- a/OrthancServer/ServerEnumerations.h Fri Dec 21 13:53:24 2012 +0100 +++ b/OrthancServer/ServerEnumerations.h Fri Dec 21 17:18:04 2012 +0100 @@ -88,7 +88,11 @@ ChangeType_NewInstance = 2, ChangeType_NewPatient = 3, ChangeType_NewSeries = 4, - ChangeType_NewStudy = 5 + ChangeType_NewStudy = 5, + ChangeType_AnonymizedStudy = 6, + ChangeType_AnonymizedSeries = 7, + ChangeType_ModifiedStudy = 8, + ChangeType_ModifiedSeries = 9 }; std::string GetBasePath(ResourceType type, diff -r 4f17834a50b6 -r fc856d175d18 OrthancServer/ServerIndex.cpp --- a/OrthancServer/ServerIndex.cpp Fri Dec 21 13:53:24 2012 +0100 +++ b/OrthancServer/ServerIndex.cpp Fri Dec 21 17:18:04 2012 +0100 @@ -663,6 +663,16 @@ result["ID"] = publicId; MainDicomTagsToJson(result, id); + std::string tmp; + + tmp = db_->GetMetadata(id, MetadataType_AnonymizedFrom); + if (tmp.size() != 0) + result["AnonymizedFrom"] = tmp; + + tmp = db_->GetMetadata(id, MetadataType_ModifiedFrom); + if (tmp.size() != 0) + result["ModifiedFrom"] = tmp; + return true; } @@ -1083,4 +1093,25 @@ return seq; } + + + + void ServerIndex::LogChange(ChangeType changeType, + const std::string& publicId) + { + boost::mutex::scoped_lock lock(mutex_); + std::auto_ptr transaction(db_->StartTransaction()); + transaction->Begin(); + + int64_t id; + ResourceType type; + if (!db_->LookupResource(publicId, id, type)) + { + throw OrthancException(ErrorCode_UnknownResource); + } + + db_->LogChange(changeType, id, type); + + transaction->Commit(); + } } diff -r 4f17834a50b6 -r fc856d175d18 OrthancServer/ServerIndex.h --- a/OrthancServer/ServerIndex.h Fri Dec 21 13:53:24 2012 +0100 +++ b/OrthancServer/ServerIndex.h Fri Dec 21 17:18:04 2012 +0100 @@ -158,5 +158,8 @@ const std::string& publicId); uint64_t IncrementGlobalSequence(GlobalProperty sequence); + + void LogChange(ChangeType changeType, + const std::string& publicId); }; }