changeset 4937:3f9b9865c8cc more-tags

include requested tags from storage if needed
author Alain Mazy <am@osimis.io>
date Mon, 14 Mar 2022 13:13:29 +0100
parents 8422e4f99a18
children f630796a59b1
files OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp OrthancServer/Sources/ServerContext.cpp OrthancServer/Sources/ServerContext.h
diffstat 3 files changed, 95 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp	Fri Mar 11 17:38:16 2022 +0100
+++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp	Mon Mar 14 13:13:29 2022 +0100
@@ -44,7 +44,7 @@
 
 // This "include" is mandatory for Release builds using Linux Standard Base
 #include <boost/math/special_functions/round.hpp>
-
+#include <boost/shared_ptr.hpp>
 
 /**
  * This semaphore is used to limit the number of concurrent HTTP
@@ -128,6 +128,9 @@
   static void AnswerListOfResources(RestApiOutput& output,
                                     ServerContext& context,
                                     const std::list<std::string>& resources,
+                                    const std::map<std::string, std::string>& instancesIds, // optional: the id of an instance for each found resource.
+                                    const std::map<std::string, boost::shared_ptr<DicomMap> >& resourcesMainDicomTags,  // optional: all tags read from DB for a resource (current level and upper levels)
+                                    const std::map<std::string, Json::Value>& resourcesDicomAsJson, // optional: the dicom-as-json for each resource
                                     ResourceType level,
                                     bool expand,
                                     DicomToJsonFormat format,
@@ -156,6 +159,22 @@
   }
 
 
+  static void AnswerListOfResources(RestApiOutput& output,
+                                    ServerContext& context,
+                                    const std::list<std::string>& resources,
+                                    ResourceType level,
+                                    bool expand,
+                                    DicomToJsonFormat format,
+                                    const std::set<DicomTag>& requestedTags)
+  {
+    std::map<std::string, std::string> unusedInstancesIds;
+    std::map<std::string, boost::shared_ptr<DicomMap> > unusedResourcesMainDicomTags;
+    std::map<std::string, Json::Value> unusedResourcesDicomAsJson;
+
+    AnswerListOfResources(output, context, resources, unusedInstancesIds, unusedResourcesMainDicomTags, unusedResourcesDicomAsJson, level, expand, format, requestedTags);
+  }
+
+
   template <enum ResourceType resourceType>
   static void ListResources(RestApiGetCall& call)
   {
@@ -2828,6 +2847,12 @@
     private:
       bool                    isComplete_;
       std::list<std::string>  resources_;
+      
+      // cache the data we used during lookup and that we could reuse when building the answers
+      std::map<std::string, std::string> instancesIds_;         // the id of an instance for each found resource.
+      std::map<std::string, boost::shared_ptr<DicomMap> > resourcesMainDicomTags_;  // all tags read from DB for a resource (current level and upper levels)
+      std::map<std::string, Json::Value> resourcesDicomAsJson_; // the dicom-as-json for a resource
+
       DicomToJsonFormat       format_;
 
     public:
@@ -2848,11 +2873,14 @@
       }
 
       virtual void Visit(const std::string& publicId,
-                         const std::string& instanceId   /* unused     */,
-                         const DicomMap& mainDicomTags   /* unused     */,
-                         const Json::Value* dicomAsJson  /* unused (*) */)  ORTHANC_OVERRIDE
+                         const std::string& instanceId,
+                         const DicomMap& mainDicomTags,
+                         const Json::Value* dicomAsJson)  ORTHANC_OVERRIDE
       {
         resources_.push_back(publicId);
+        instancesIds_[publicId] = instanceId;
+        resourcesMainDicomTags_[publicId].reset(mainDicomTags.Clone());
+        resourcesDicomAsJson_[publicId] = dicomAsJson;
       }
 
       void Answer(RestApiOutput& output,
--- a/OrthancServer/Sources/ServerContext.cpp	Fri Mar 11 17:38:16 2022 +0100
+++ b/OrthancServer/Sources/ServerContext.cpp	Mon Mar 14 13:13:29 2022 +0100
@@ -1396,6 +1396,7 @@
 
       bool hasOnlyMainDicomTags;
       DicomMap dicom;
+      DicomMap allMainDicomTagsFromDB;
       
       if (findStorageAccessMode_ == FindStorageAccessMode_DatabaseOnly ||
           findStorageAccessMode_ == FindStorageAccessMode_DiskOnAnswer ||
@@ -1404,8 +1405,7 @@
         // Case (1): The main DICOM tags, as stored in the database,
         // are sufficient to look for match
 
-        DicomMap tmp;
-        if (!GetIndex().GetAllMainDicomTags(tmp, instances[i]))
+        if (!GetIndex().GetAllMainDicomTags(allMainDicomTagsFromDB, instances[i]))  // MORE_TAGS: TODO: we could read only the current and upper level to reduce the number of SQL queries
         {
           // The instance has been removed during the execution of the
           // lookup, ignore it
@@ -1418,16 +1418,16 @@
         {
           // WARNING: Don't reorder cases below, and don't add "break"
           case ResourceType_Instance:
-            dicom.MergeMainDicomTags(tmp, ResourceType_Instance);
+            dicom.MergeMainDicomTags(allMainDicomTagsFromDB, ResourceType_Instance);
 
           case ResourceType_Series:
-            dicom.MergeMainDicomTags(tmp, ResourceType_Series);
+            dicom.MergeMainDicomTags(allMainDicomTagsFromDB, ResourceType_Series);
 
           case ResourceType_Study:
-            dicom.MergeMainDicomTags(tmp, ResourceType_Study);
+            dicom.MergeMainDicomTags(allMainDicomTagsFromDB, ResourceType_Study);
             
           case ResourceType_Patient:
-            dicom.MergeMainDicomTags(tmp, ResourceType_Patient);
+            dicom.MergeMainDicomTags(allMainDicomTagsFromDB, ResourceType_Patient);
             break;
 
           default:
@@ -1476,7 +1476,7 @@
           if (hasOnlyMainDicomTags)
           {
             // This is Case (1): The variable "dicom" only contains the main DICOM tags
-            visitor.Visit(resources[i], instances[i], dicom, dicomAsJson.get());
+            visitor.Visit(resources[i], instances[i], allMainDicomTagsFromDB, dicomAsJson.get());
           }
           else
           {
@@ -2262,12 +2262,25 @@
                                      DicomToJsonFormat format,
                                      const std::set<DicomTag>& requestedTags)
   {
+    std::string unusedInstanceId;
+    Json::Value unusedValue;
+
+    return ExpandResource(target, publicId, unusedInstanceId, unusedValue, level, format, requestedTags);
+  }
+
+  bool ServerContext::ExpandResource(Json::Value& target,
+                                     const std::string& publicId,
+                                     const std::string& instanceId,    // optional: the id of an instance for the resource
+                                     const Json::Value& dicomAsJson,   // optional: the dicom-as-json for the resource
+                                     ResourceType level,
+                                     DicomToJsonFormat format,
+                                     const std::set<DicomTag>& requestedTags)
+  {
     ExpandedResource resource;
 
     if (GetIndex().ExpandResource(resource, publicId, level, format, requestedTags))
     {
       // check the main dicom tags list has not changed since the resource was stored
-
       if (resource.mainDicomTagsSignature_ != DicomMap::GetMainDicomTagsSignature(resource.type_))
       {
         OrthancConfiguration::ReaderLock lock;
@@ -2277,9 +2290,40 @@
         }
       }
 
-      // MORE_TAGS: TODO: possibly merge missing requested tags from /tags
-      // log warning
-      // use resource.missingRequestedTags_
+      // possibly merge missing requested tags from dicom-as-json
+      if (!resource.missingRequestedTags_.empty())
+      {
+        std::string instanceId_ = instanceId;
+        Json::Value dicomAsJson_ = dicomAsJson;
+        if (dicomAsJson_.isNull())
+        {
+          if (instanceId_.empty())
+          {
+            if (level == ResourceType_Instance)
+            {
+              instanceId_ = publicId;
+            }
+            else
+            {
+              std::list<std::string> instancesIds;
+              GetIndex().GetChildInstances(instancesIds, publicId);
+              if (instancesIds.size() < 1)
+              {
+                throw OrthancException(ErrorCode_InternalError, "ExpandResource: no instances found");
+              }
+              instanceId_ = instancesIds.front();
+            }
+          }
+  
+          // MORE_TAGS :TODO: log warning (add an option to disable them)
+          ReadDicomAsJson(dicomAsJson_, instanceId_);
+        }
+
+        DicomMap allTags;
+        allTags.FromDicomAsJson(dicomAsJson_);
+
+        resource.tags_.Merge(allTags);
+      }
 
       SerializeExpandedResource(target, resource, format, requestedTags);
 
--- a/OrthancServer/Sources/ServerContext.h	Fri Mar 11 17:38:16 2022 +0100
+++ b/OrthancServer/Sources/ServerContext.h	Mon Mar 14 13:13:29 2022 +0100
@@ -546,5 +546,13 @@
                         DicomToJsonFormat format,
                         const std::set<DicomTag>& requestedTags);
 
+    bool ExpandResource(Json::Value& target,
+                        const std::string& publicId,
+                        const std::string& instanceId,    // optional: the id of an instance for the resource
+                        const Json::Value& dicomAsJson,   // optional: the dicom-as-json for the resource
+                        ResourceType level,
+                        DicomToJsonFormat format,
+                        const std::set<DicomTag>& requestedTags);
+
   };
 }