diff OrthancServer/Sources/Database/FindResponse.cpp @ 5586:fc3914c07dd3 find-refactoring

refactoring FindResponse
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 03 May 2024 17:02:02 +0200
parents 74cc31c8db2b
children 1b0fc6685f57
line wrap: on
line diff
--- a/OrthancServer/Sources/Database/FindResponse.cpp	Sat Apr 27 22:15:37 2024 +0200
+++ b/OrthancServer/Sources/Database/FindResponse.cpp	Fri May 03 17:02:02 2024 +0200
@@ -30,101 +30,189 @@
 
 namespace Orthanc
 {
-  static void ExtractOrthancIdentifiers(OrthancIdentifiers& identifiers,
-                                        ResourceType level,
-                                        const DicomMap& dicom)
+  class FindResponse::DicomTagsAtLevel::DicomValue : public boost::noncopyable
+  {
+  public:
+    enum ValueType
+    {
+      ValueType_String,
+      ValueType_Null
+    };
+
+  private:
+    ValueType     type_;
+    std::string   value_;
+
+  public:
+    DicomValue(ValueType type,
+               const std::string& value) :
+      type_(type),
+      value_(value)
+    {
+    }
+
+    ValueType GetType() const
+    {
+      return type_;
+    }
+
+    const std::string& GetValue() const
+    {
+      switch (type_)
+      {
+        case ValueType_Null:
+          throw OrthancException(ErrorCode_BadSequenceOfCalls);
+
+        case ValueType_String:
+          return value_;
+
+        default:
+          throw OrthancException(ErrorCode_ParameterOutOfRange);
+      }
+    }
+  };
+
+
+  FindResponse::DicomTagsAtLevel::~DicomTagsAtLevel()
+  {
+    for (Content::iterator it = content_.begin(); it != content_.end(); ++it)
+    {
+      assert(it->second != NULL);
+      delete it->second;
+    }
+  }
+
+
+  void FindResponse::DicomTagsAtLevel::AddNullValue(uint16_t group,
+                                                    uint16_t element)
+  {
+    const DicomTag tag(group, element);
+
+    if (content_.find(tag) == content_.end())
+    {
+      content_[tag] = new DicomValue(DicomValue::ValueType_Null, "");
+    }
+    else
+    {
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+  }
+
+
+  void FindResponse::DicomTagsAtLevel::AddStringValue(uint16_t group,
+                                                      uint16_t element,
+                                                      const std::string& value)
+  {
+    const DicomTag tag(group, element);
+
+    if (content_.find(tag) == content_.end())
+    {
+      content_[tag] = new DicomValue(DicomValue::ValueType_String, value);
+    }
+    else
+    {
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+  }
+
+
+  void FindResponse::DicomTagsAtLevel::Fill(DicomMap& target) const
+  {
+    for (Content::const_iterator it = content_.begin(); it != content_.end(); ++it)
+    {
+      assert(it->second != NULL);
+
+      switch (it->second->GetType())
+      {
+        case DicomValue::ValueType_String:
+          target.SetValue(it->first, it->second->GetValue(), false /* not binary */);
+          break;
+
+        case DicomValue::ValueType_Null:
+          target.SetNullValue(it->first);
+          break;
+
+        default:
+          throw OrthancException(ErrorCode_InternalError);
+      }
+    }
+  }
+
+
+  void FindResponse::ChildrenAtLevel::AddIdentifier(const std::string& identifier)
+  {
+    if (identifiers_.find(identifier) == identifiers_.end())
+    {
+      identifiers_.insert(identifier);
+    }
+    else
+    {
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+  }
+
+
+  FindResponse::DicomTagsAtLevel& FindResponse::Item::GetDicomTagsAtLevel(ResourceType level)
   {
     switch (level)
     {
       case ResourceType_Patient:
-      {
-        std::string patientId;
-        if (!dicom.LookupStringValue(patientId, Orthanc::DICOM_TAG_PATIENT_ID, false))
-        {
-          throw OrthancException(ErrorCode_ParameterOutOfRange);
-        }
-        else
-        {
-          DicomInstanceHasher hasher(patientId, "", "", "");
-          identifiers.SetPatientId(hasher.HashPatient());
-        }
-        break;
-      }
+        return patientTags_;
 
       case ResourceType_Study:
-      {
-        std::string patientId, studyInstanceUid;
-        if (!dicom.LookupStringValue(patientId, Orthanc::DICOM_TAG_PATIENT_ID, false) ||
-            !dicom.LookupStringValue(studyInstanceUid, Orthanc::DICOM_TAG_STUDY_INSTANCE_UID, false))
-        {
-          throw OrthancException(ErrorCode_ParameterOutOfRange);
-        }
-        else
-        {
-          DicomInstanceHasher hasher(patientId, studyInstanceUid, "", "");
-          identifiers.SetPatientId(hasher.HashPatient());
-          identifiers.SetStudyId(hasher.HashStudy());
-        }
-        break;
-      }
+        return studyTags_;
 
       case ResourceType_Series:
-      {
-        std::string patientId, studyInstanceUid, seriesInstanceUid;
-        if (!dicom.LookupStringValue(patientId, Orthanc::DICOM_TAG_PATIENT_ID, false) ||
-            !dicom.LookupStringValue(studyInstanceUid, Orthanc::DICOM_TAG_STUDY_INSTANCE_UID, false) ||
-            !dicom.LookupStringValue(seriesInstanceUid, Orthanc::DICOM_TAG_SERIES_INSTANCE_UID, false))
-        {
-          throw OrthancException(ErrorCode_ParameterOutOfRange);
-        }
-        else
-        {
-          DicomInstanceHasher hasher(patientId, studyInstanceUid, seriesInstanceUid, "");
-          identifiers.SetPatientId(hasher.HashPatient());
-          identifiers.SetStudyId(hasher.HashStudy());
-          identifiers.SetSeriesId(hasher.HashSeries());
-        }
-        break;
-      }
+        return seriesTags_;
 
       case ResourceType_Instance:
-      {
-        std::string patientId, studyInstanceUid, seriesInstanceUid, sopInstanceUid;
-        if (!dicom.LookupStringValue(patientId, Orthanc::DICOM_TAG_PATIENT_ID, false) ||
-            !dicom.LookupStringValue(studyInstanceUid, Orthanc::DICOM_TAG_STUDY_INSTANCE_UID, false) ||
-            !dicom.LookupStringValue(seriesInstanceUid, Orthanc::DICOM_TAG_SERIES_INSTANCE_UID, false) ||
-            !dicom.LookupStringValue(sopInstanceUid, Orthanc::DICOM_TAG_SOP_INSTANCE_UID, false))
-        {
-          throw OrthancException(ErrorCode_ParameterOutOfRange);
-        }
-        else
-        {
-          DicomInstanceHasher hasher(patientId, studyInstanceUid, seriesInstanceUid, sopInstanceUid);
-          identifiers.SetPatientId(hasher.HashPatient());
-          identifiers.SetStudyId(hasher.HashStudy());
-          identifiers.SetSeriesId(hasher.HashSeries());
-          identifiers.SetInstanceId(hasher.HashInstance());
-        }
-        break;
-      }
+        return instanceTags_;
 
       default:
-        throw OrthancException(ErrorCode_NotImplemented);
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
     }
   }
 
 
-  FindResponse::Item::Item(ResourceType level,
-                           DicomMap* dicomMap /* takes ownership */) :
-    dicomMap_(dicomMap)
+  FindResponse::ChildrenAtLevel& FindResponse::Item::GetChildrenAtLevel(ResourceType level)
   {
-    if (dicomMap == NULL)
+    switch (level)
     {
-      throw OrthancException(ErrorCode_NullPointer);
-    }
-    else
-    {
-      ExtractOrthancIdentifiers(identifiers_, level, *dicomMap);
+      case ResourceType_Study:
+        if (level_ == ResourceType_Patient)
+        {
+          return childrenStudies_;
+        }
+        else
+        {
+          throw OrthancException(ErrorCode_BadParameterType);
+        }
+
+      case ResourceType_Series:
+        if (level_ == ResourceType_Patient ||
+            level_ == ResourceType_Study)
+        {
+          return childrenSeries_;
+        }
+        else
+        {
+          throw OrthancException(ErrorCode_BadParameterType);
+        }
+
+      case ResourceType_Instance:
+        if (level_ == ResourceType_Patient ||
+            level_ == ResourceType_Study ||
+            level_ == ResourceType_Series)
+        {
+          return childrenInstances_;
+        }
+        else
+        {
+          throw OrthancException(ErrorCode_BadParameterType);
+        }
+
+      default:
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
     }
   }
 
@@ -170,16 +258,90 @@
     }
   }
 
+  const std::string& FindResponse::Item::GetParentIdentifier() const
+  {
+    if (level_ == ResourceType_Patient)
+    {
+      throw OrthancException(ErrorCode_BadParameterType);
+    }
+    else if (HasParentIdentifier())
+    {
+      return *parentIdentifier_;
+    }
+    else
+    {
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+  }
 
-  const DicomMap& FindResponse::Item::GetDicomMap() const
+
+  void FindResponse::Item::SetParentIdentifier(const std::string& id)
   {
-    if (dicomMap_.get() == NULL)
+    if (level_ == ResourceType_Patient)
+    {
+      throw OrthancException(ErrorCode_BadParameterType);
+    }
+    else if (HasParentIdentifier())
     {
       throw OrthancException(ErrorCode_BadSequenceOfCalls);
     }
     else
     {
-      return *dicomMap_;
+      parentIdentifier_.reset(new std::string(id));
+    }
+  }
+
+
+  bool FindResponse::Item::HasParentIdentifier() const
+  {
+    if (level_ == ResourceType_Patient)
+    {
+      throw OrthancException(ErrorCode_BadParameterType);
+    }
+    else
+    {
+      return parentIdentifier_.get() != NULL;
+    }
+  }
+
+
+  void FindResponse::Item::AddLabel(const std::string& label)
+  {
+    if (labels_.find(label) == labels_.end())
+    {
+      labels_.insert(label);
+    }
+    else
+    {
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+  }
+
+
+  void FindResponse::Item::AddAttachment(const FileInfo& attachment)
+  {
+    if (attachments_.find(attachment.GetContentType()) == attachments_.end())
+    {
+      attachments_[attachment.GetContentType()] = attachment;
+    }
+    else
+    {
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+  }
+
+
+  bool FindResponse::Item::LookupAttachment(FileInfo& target, FileContentType type) const
+  {
+    std::map<FileContentType, FileInfo>::const_iterator it = attachments_.find(type);
+    if (it != attachments_.end())
+    {
+      target = it->second;
+      return true;
+    }
+    else
+    {
+      return false;
     }
   }
 
@@ -196,13 +358,25 @@
 
   void FindResponse::Add(Item* item /* takes ownership */)
   {
+    std::unique_ptr<Item> protection(item);
+
     if (item == NULL)
     {
       throw OrthancException(ErrorCode_NullPointer);
     }
     else
     {
-      items_.push_back(item);
+      const std::string& id = item->GetIdentifier();
+
+      if (index_.find(id) == index_.end())
+      {
+        items_.push_back(protection.release());
+        index_[id] = item;
+      }
+      else
+      {
+        throw OrthancException(ErrorCode_BadSequenceOfCalls, "This resource has already been added: " + id);
+      }
     }
   }
 
@@ -220,20 +394,19 @@
     }
   }
 
-  void FindResponse::Item::AddDicomTag(uint16_t group, uint16_t element, const std::string& value, bool isBinary)
+
+  const FindResponse::Item* FindResponse::LookupItem(const std::string& id) const
   {
-    if (dicomMap_.get() == NULL)
+    Index::const_iterator found = index_.find(id);
+
+    if (found == index_.end())
     {
-      dicomMap_.reset(new DicomMap());
+      return NULL;
     }
-
-    dicomMap_->SetValue(group, element, value, isBinary);
+    else
+    {
+      assert(found->second != NULL);
+      return found->second;
+    }
   }
-
-  void FindResponse::Item::AddChild(const std::string& childId)
-  {
-    children_.push_back(childId);
-  }
-
-
 }