diff OrthancServer/Sources/ResourceFinder.cpp @ 5665:d8c86698110c find-refactoring

implemented computed tag: Instance Availability
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 04 Jul 2024 14:36:24 +0200
parents 3f13db27b399
children aa231c18b9d2
line wrap: on
line diff
--- a/OrthancServer/Sources/ResourceFinder.cpp	Thu Jul 04 11:59:50 2024 +0200
+++ b/OrthancServer/Sources/ResourceFinder.cpp	Thu Jul 04 14:36:24 2024 +0200
@@ -421,6 +421,8 @@
         request_.GetParentRetrieveSpecification(ResourceType_Study).SetRetrieveMetadata(true);
         requestedStudyTags_.insert(tag);
       }
+
+      hasRequestedTags_ = true;
     }
     else if (DicomMap::IsMainDicomTag(tag, ResourceType_Study))
     {
@@ -437,6 +439,8 @@
         request_.GetParentRetrieveSpecification(ResourceType_Study).SetRetrieveMetadata(true);
         requestedStudyTags_.insert(tag);
       }
+
+      hasRequestedTags_ = true;
     }
     else if (DicomMap::IsMainDicomTag(tag, ResourceType_Series))
     {
@@ -454,6 +458,8 @@
         request_.GetParentRetrieveSpecification(ResourceType_Series).SetRetrieveMetadata(true);
         requestedSeriesTags_.insert(tag);
       }
+
+      hasRequestedTags_ = true;
     }
     else if (DicomMap::IsMainDicomTag(tag, ResourceType_Instance))
     {
@@ -473,19 +479,36 @@
         assert(request_.IsRetrieveMetadata());
         requestedInstanceTags_.insert(tag);
       }
+
+      hasRequestedTags_ = true;
+    }
+    else if (tag == DICOM_TAG_INSTANCE_AVAILABILITY)
+    {
+      requestedComputedTags_.insert(tag);
+      hasRequestedTags_ = true;
+    }
+    else if (tag == DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES)
+    {
+      if (request_.GetLevel() == ResourceType_Series)
+      {
+        requestedComputedTags_.insert(tag);
+        hasRequestedTags_ = true;
+        request_.GetChildrenRetrieveSpecification(ResourceType_Instance).SetRetrieveCount(true);
+      }
     }
     else
     {
-      // This is not a main DICOM tag: We will be forced to access the DICOM file anyway
+      // This is neither a main DICOM tag, nor a computed DICOM tag:
+      // We will be forced to access the DICOM file anyway
       requestedTagsFromFileStorage_.insert(tag);
 
       if (request_.GetLevel() != ResourceType_Instance)
       {
         request_.SetRetrieveOneInstanceIdentifier(true);
       }
+
+      hasRequestedTags_ = true;
     }
-
-    hasRequestedTags_ = true;
   }
 
 
@@ -498,6 +521,111 @@
   }
 
 
+  void ResourceFinder::InjectComputedTags(DicomMap& requestedTags,
+                                          const FindResponse::Resource& resource) const
+  {
+    switch (resource.GetLevel())
+    {
+      case ResourceType_Patient:
+        break;
+
+      case ResourceType_Study:
+        break;
+
+      case ResourceType_Series:
+        if (IsRequestedComputedTag(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES))
+        {
+          requestedTags.SetValue(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES,
+                                 boost::lexical_cast<std::string>(resource.GetChildrenIdentifiers().size()), false);
+        }
+        break;
+
+      case ResourceType_Instance:
+        if (IsRequestedComputedTag(DICOM_TAG_INSTANCE_AVAILABILITY))
+        {
+          requestedTags.SetValue(DICOM_TAG_INSTANCE_AVAILABILITY, "ONLINE", false);
+        }
+        break;
+
+      default:
+        throw OrthancException(ErrorCode_InternalError);
+    }
+  }
+
+
+  static void ReadMissingTagsFromStorageArea(DicomMap& requestedTags,
+                                             ServerContext& context,
+                                             const FindRequest& request,
+                                             const FindResponse::Resource& resource,
+                                             const std::set<DicomTag>& missingTags)
+  {
+    OrthancConfiguration::ReaderLock lock;
+    if (lock.GetConfiguration().IsWarningEnabled(Warnings_001_TagsBeingReadFromStorage))
+    {
+      std::string missings;
+      FromDcmtkBridge::FormatListOfTags(missings, missingTags);
+
+      LOG(WARNING) << "W001: Accessing Dicom tags from storage when accessing "
+                   << Orthanc::GetResourceTypeText(resource.GetLevel(), false, false)
+                   << ": " << missings;
+    }
+
+    std::string instancePublicId;
+
+    if (request.IsRetrieveOneInstanceIdentifier())
+    {
+      instancePublicId = resource.GetOneInstanceIdentifier();
+    }
+    else if (request.GetLevel() == ResourceType_Instance)
+    {
+      instancePublicId = resource.GetIdentifier();
+    }
+    else
+    {
+      FindRequest requestDicomAttachment(request.GetLevel());
+      requestDicomAttachment.SetOrthancId(request.GetLevel(), resource.GetIdentifier());
+      requestDicomAttachment.SetRetrieveOneInstanceIdentifier(true);
+
+      FindResponse responseDicomAttachment;
+      context.GetIndex().ExecuteFind(responseDicomAttachment, requestDicomAttachment);
+
+      if (responseDicomAttachment.GetSize() != 1 ||
+          !responseDicomAttachment.GetResourceByIndex(0).HasOneInstanceIdentifier())
+      {
+        throw OrthancException(ErrorCode_InexistentFile);
+      }
+      else
+      {
+        instancePublicId = responseDicomAttachment.GetResourceByIndex(0).GetOneInstanceIdentifier();
+      }
+    }
+
+    LOG(INFO) << "Will retrieve missing DICOM tags from instance: " << instancePublicId;
+
+    // TODO-FIND: What do we do if the DICOM has been removed since the request?
+    // Do we fail, or do we skip the resource?
+
+    Json::Value tmpDicomAsJson;
+    context.ReadDicomAsJson(tmpDicomAsJson, instancePublicId, missingTags /* ignoreTagLength */);
+
+    DicomMap tmpDicomMap;
+    tmpDicomMap.FromDicomAsJson(tmpDicomAsJson, false /* append */, true /* parseSequences*/);
+
+    for (std::set<DicomTag>::const_iterator it = missingTags.begin(); it != missingTags.end(); ++it)
+    {
+      assert(!requestedTags.HasTag(*it));
+      if (tmpDicomMap.HasTag(*it))
+      {
+        requestedTags.SetValue(*it, tmpDicomMap.GetValue(*it));
+      }
+      else
+      {
+        requestedTags.SetNullValue(*it);  // TODO-FIND: Is this compatible with Orthanc <= 1.12.3?
+      }
+    }
+  }
+
+
   void ResourceFinder::Execute(Json::Value& target,
                                ServerContext& context) const
   {
@@ -521,90 +649,30 @@
         Json::Value item;
         Expand(item, resource, context.GetIndex());
 
-        std::set<DicomTag> missingTags = requestedTagsFromFileStorage_;
-
-        DicomMap requestedTags;
-        InjectRequestedTags(requestedTags, missingTags, resource, ResourceType_Patient, requestedPatientTags_);
-        InjectRequestedTags(requestedTags, missingTags, resource, ResourceType_Study, requestedStudyTags_);
-        InjectRequestedTags(requestedTags, missingTags, resource, ResourceType_Series, requestedSeriesTags_);
-        InjectRequestedTags(requestedTags, missingTags, resource, ResourceType_Instance, requestedInstanceTags_);
-
-        if (!missingTags.empty())
+        if (hasRequestedTags_)
         {
-          if (!allowStorageAccess_)
-          {
-            throw OrthancException(ErrorCode_BadSequenceOfCalls,
-                                   "Cannot add missing requested tags, as access to file storage is disallowed");
-          }
-
-          OrthancConfiguration::ReaderLock lock;
-          if (lock.GetConfiguration().IsWarningEnabled(Warnings_001_TagsBeingReadFromStorage))
-          {
-            std::string missings;
-            FromDcmtkBridge::FormatListOfTags(missings, missingTags);
+          DicomMap requestedTags;
+          InjectComputedTags(requestedTags, resource);
 
-            LOG(WARNING) << "W001: Accessing Dicom tags from storage when accessing "
-                         << Orthanc::GetResourceTypeText(resource.GetLevel(), false, false)
-                         << ": " << missings;
-          }
+          std::set<DicomTag> missingTags = requestedTagsFromFileStorage_;
+          InjectRequestedTags(requestedTags, missingTags, resource, ResourceType_Patient, requestedPatientTags_);
+          InjectRequestedTags(requestedTags, missingTags, resource, ResourceType_Study, requestedStudyTags_);
+          InjectRequestedTags(requestedTags, missingTags, resource, ResourceType_Series, requestedSeriesTags_);
+          InjectRequestedTags(requestedTags, missingTags, resource, ResourceType_Instance, requestedInstanceTags_);
 
-          std::string instancePublicId;
-
-          if (request_.IsRetrieveOneInstanceIdentifier())
-          {
-            instancePublicId = resource.GetOneInstanceIdentifier();
-          }
-          else if (request_.GetLevel() == ResourceType_Instance)
+          if (!missingTags.empty())
           {
-            instancePublicId = resource.GetIdentifier();
-          }
-          else
-          {
-            FindRequest requestDicomAttachment(request_.GetLevel());
-            requestDicomAttachment.SetOrthancId(request_.GetLevel(), resource.GetIdentifier());
-            requestDicomAttachment.SetRetrieveOneInstanceIdentifier(true);
-
-            FindResponse responseDicomAttachment;
-            context.GetIndex().ExecuteFind(responseDicomAttachment, requestDicomAttachment);
-
-            if (responseDicomAttachment.GetSize() != 1 ||
-                !responseDicomAttachment.GetResourceByIndex(0).HasOneInstanceIdentifier())
+            if (!allowStorageAccess_)
             {
-              throw OrthancException(ErrorCode_InexistentFile);
+              throw OrthancException(ErrorCode_BadSequenceOfCalls,
+                                     "Cannot add missing requested tags, as access to file storage is disallowed");
             }
             else
             {
-              instancePublicId = responseDicomAttachment.GetResourceByIndex(0).GetOneInstanceIdentifier();
+              ReadMissingTagsFromStorageArea(requestedTags, context, request_, resource, missingTags);
             }
           }
 
-          LOG(INFO) << "Will retrieve missing DICOM tags from instance: " << instancePublicId;
-
-          // TODO-FIND: What do we do if the DICOM has been removed since the request?
-          // Do we fail, or do we skip the resource?
-
-          Json::Value tmpDicomAsJson;
-          context.ReadDicomAsJson(tmpDicomAsJson, instancePublicId, missingTags /* ignoreTagLength */);
-
-          DicomMap tmpDicomMap;
-          tmpDicomMap.FromDicomAsJson(tmpDicomAsJson, false /* append */, true /* parseSequences*/);
-
-          for (std::set<DicomTag>::const_iterator it = missingTags.begin(); it != missingTags.end(); ++it)
-          {
-            assert(!requestedTags.HasTag(*it));
-            if (tmpDicomMap.HasTag(*it))
-            {
-              requestedTags.SetValue(*it, tmpDicomMap.GetValue(*it));
-            }
-            else
-            {
-              requestedTags.SetNullValue(*it);  // TODO-FIND: Is this compatible with Orthanc <= 1.12.3?
-            }
-          }
-        }
-
-        if (hasRequestedTags_)
-        {
           static const char* const REQUESTED_TAGS = "RequestedTags";
           item[REQUESTED_TAGS] = Json::objectValue;
           FromDcmtkBridge::ToJson(item[REQUESTED_TAGS], requestedTags, format_);