changeset 315:fc856d175d18

modifications
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 21 Dec 2012 17:18:04 +0100
parents 4f17834a50b6
children d526ac73c886
files Core/DicomFormat/DicomInstanceHasher.cpp Core/DicomFormat/DicomInstanceHasher.h OrthancServer/FromDcmtkBridge.cpp OrthancServer/FromDcmtkBridge.h OrthancServer/OrthancRestApi.cpp OrthancServer/ServerEnumerations.cpp OrthancServer/ServerEnumerations.h OrthancServer/ServerIndex.cpp OrthancServer/ServerIndex.h
diffstat 9 files changed, 171 insertions(+), 52 deletions(-) [+]
line wrap: on
line diff
--- 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)
--- 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_;
--- 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();
--- 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
--- 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<std::string> 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<std::string> 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<ParsedDicomFile> modified(dicom.Clone());
+        ParsedDicomFile& original = context.GetDicomFile(*it);
+        std::auto_ptr<ParsedDicomFile> 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<std::string> Instances;
     typedef std::map<std::string, std::string> 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<ParsedDicomFile> modified(dicom.Clone());
+        std::auto_ptr<ParsedDicomFile> 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;
--- 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);
     }
--- 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,
--- 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<SQLite::Transaction> 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();
+  }
 }
--- 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);
   };
 }