changeset 525:a4c93eea9403

Refactored the way WADO-RS locate resources
author Alain Mazy <am@osimis.io>
date Wed, 29 Jun 2022 10:22:25 +0200
parents 43d4ba62a9ba
children 389445feb3a0
files NEWS Plugin/WadoRs.cpp TODO
diffstat 3 files changed, 84 insertions(+), 120 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Tue Jun 28 18:37:28 2022 +0200
+++ b/NEWS	Wed Jun 29 10:22:25 2022 +0200
@@ -4,6 +4,8 @@
 * if using "MainDicomTags" mode for "SeriesMetadata" and "StudiesMetadata",
   the plugin now returns the "ExtraMainDicomTags" that have been configured on Orthanc side.
 * Now able to return sequences stored in "ExtraMainDicomTags" (with Orthanc 1.11.1)
+* refactored the way WADO-RS locate resources.  If the same SeriesInstanceUID is re-used
+  across multiple Studies, the plugin should now locate it correctly.
 
 Version 1.8 (2022-05-09)
 ========================
--- a/Plugin/WadoRs.cpp	Tue Jun 28 18:37:28 2022 +0200
+++ b/Plugin/WadoRs.cpp	Wed Jun 29 10:22:25 2022 +0200
@@ -801,12 +801,13 @@
 #endif
 }
 
-
-
-bool LocateStudy(OrthancPluginRestOutput* output,
-                 std::string& orthancId,
-                 std::string& studyInstanceUid,
-                 const OrthancPluginHttpRequest* request)
+bool LocateResource(OrthancPluginRestOutput* output,
+                    std::string& orthancId,
+                    std::string& studyInstanceUid,
+                    std::string& seriesInstanceUid,
+                    std::string& sopInstanceUid,
+                    const std::string& level,
+                    const OrthancPluginHttpRequest* request)
 {
   OrthancPluginContext* context = OrthancPlugins::GetGlobalContext();
 
@@ -816,25 +817,68 @@
     return false;
   }
 
+  {
+    std::string body;
+    Json::Value payload;
+    Json::Value payloadQuery;
+
+    payload["Level"] = level;
+    
+    if (!sopInstanceUid.empty())
+    {
+      payloadQuery["SOPInstanceUID"] = sopInstanceUid;
+    }
+    
+    if (!seriesInstanceUid.empty())
+    {
+      payloadQuery["SeriesInstanceUID"] = seriesInstanceUid;
+    }
+
+    payloadQuery["StudyInstanceUID"] = studyInstanceUid;
+    payload["Query"] = payloadQuery;
+
+    OrthancPlugins::WriteFastJson(body, payload);
+    
+    Json::Value resources;
+    if (!OrthancPlugins::RestApiPost(resources, "/tools/find", body, false) ||
+        resources.type() != Json::arrayValue)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+    }
+
+    if (resources.size() == 0)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentItem,
+                                      "Accessing an inexistent " + level + " with WADO-RS: " + studyInstanceUid + "/" + seriesInstanceUid + "/" + sopInstanceUid);
+    }
+    if (resources.size() > 1)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentItem,
+                                      "Multiple " + level + " found for WADO-RS: " + studyInstanceUid + "/" + seriesInstanceUid + "/" + sopInstanceUid);
+    }
+    orthancId = resources[0].asString();
+    return true;
+  }
+}
+
+
+
+bool LocateStudy(OrthancPluginRestOutput* output,
+                 std::string& orthancId,
+                 std::string& studyInstanceUid,
+                 const OrthancPluginHttpRequest* request)
+{
+  std::string sopInstanceUid;
+  std::string seriesInstanceUid;
   studyInstanceUid = request->groups[0];
 
-  try
-  {
-    OrthancPlugins::OrthancString tmp;
-    tmp.Assign(OrthancPluginLookupStudy(context, studyInstanceUid.c_str()));
-
-    if (tmp.GetContent() != NULL)
-    {
-      tmp.ToString(orthancId);
-      return true;
-    }
-  }
-  catch (Orthanc::OrthancException&)
-  {
-  }
-
-  throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentItem, 
-                                  "Accessing an inexistent study with WADO-RS: " + studyInstanceUid);
+  return LocateResource(output,
+                        orthancId,
+                        studyInstanceUid,
+                        seriesInstanceUid,
+                        sopInstanceUid,
+                        "Study",
+                        request);
 }
 
 
@@ -844,55 +888,17 @@
                   std::string& seriesInstanceUid,
                   const OrthancPluginHttpRequest* request)
 {
-  OrthancPluginContext* context = OrthancPlugins::GetGlobalContext();
-
-  if (request->method != OrthancPluginHttpMethod_Get)
-  {
-    OrthancPluginSendMethodNotAllowed(context, output, "GET");
-    return false;
-  }
-
+  std::string sopInstanceUid;
   studyInstanceUid = request->groups[0];
   seriesInstanceUid = request->groups[1];
 
-  bool found = false;
-
-  try
-  {
-    OrthancPlugins::OrthancString tmp;
-    tmp.Assign(OrthancPluginLookupSeries(context, seriesInstanceUid.c_str()));
-
-    if (tmp.GetContent() != NULL)
-    {
-      tmp.ToString(orthancId);
-      found = true;
-    }
-  }
-  catch (Orthanc::OrthancException&)
-  {
-  }
-
-  if (!found)
-  {
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentItem, 
-                                    "Accessing an inexistent series with WADO-RS: " + seriesInstanceUid);
-  }
-  
-  Json::Value study;
-  if (!OrthancPlugins::RestApiGet(study, "/series/" + orthancId + "/study", false))
-  {
-    OrthancPluginSendHttpStatusCode(context, output, 404);
-    return false;
-  }
-  else if (study[MAIN_DICOM_TAGS]["StudyInstanceUID"].asString() != studyInstanceUid)
-  {
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentItem, 
-                                    "No series " + seriesInstanceUid + " in study " + studyInstanceUid);
-  }
-  else
-  {
-    return true;
-  }
+  return LocateResource(output,
+                        orthancId,
+                        studyInstanceUid,
+                        seriesInstanceUid,
+                        sopInstanceUid,
+                        "Series",
+                        request);
 }
 
 
@@ -903,50 +909,17 @@
                     std::string& sopInstanceUid,
                     const OrthancPluginHttpRequest* request)
 {
-  OrthancPluginContext* context = OrthancPlugins::GetGlobalContext();
-
-  if (request->method != OrthancPluginHttpMethod_Get)
-  {
-    OrthancPluginSendMethodNotAllowed(context, output, "GET");
-    return false;
-  }
-
   studyInstanceUid = request->groups[0];
   seriesInstanceUid = request->groups[1];
   sopInstanceUid = request->groups[2];
-  
-  {
-    OrthancPlugins::OrthancString tmp;
-    tmp.Assign(OrthancPluginLookupInstance(context, sopInstanceUid.c_str()));
 
-    if (tmp.GetContent() == NULL)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentItem,
-                                      "Accessing an inexistent instance with WADO-RS: " + sopInstanceUid);
-    }
-
-    tmp.ToString(orthancId);
-  }
-  
-  Json::Value study, series;
-  if (!OrthancPlugins::RestApiGet(series, "/instances/" + orthancId + "/series", false) ||
-      !OrthancPlugins::RestApiGet(study, "/instances/" + orthancId + "/study", false))
-  {
-    OrthancPluginSendHttpStatusCode(context, output, 404);
-    return false;
-  }
-  else if (study[MAIN_DICOM_TAGS]["StudyInstanceUID"].asString() != studyInstanceUid ||
-           series[MAIN_DICOM_TAGS]["SeriesInstanceUID"].asString() != seriesInstanceUid)
-  {
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentItem,
-                                    "Instance " + sopInstanceUid + 
-                                    " is not both in study " + studyInstanceUid +
-                                    " and in series " + seriesInstanceUid);
-  }
-  else
-  {
-    return true;
-  }
+  return LocateResource(output,
+                        orthancId,
+                        studyInstanceUid,
+                        seriesInstanceUid,
+                        sopInstanceUid,
+                        "Instance",
+                        request);
 }
 
 
--- a/TODO	Tue Jun 28 18:37:28 2022 +0200
+++ b/TODO	Wed Jun 29 10:22:25 2022 +0200
@@ -1,17 +1,6 @@
 * Implement capabilities: https://www.dicomstandard.org/using/dicomweb/capabilities/
   from https://groups.google.com/d/msgid/orthanc-users/c60227f2-c6da-4fd9-9b03-3ce9bf7d1af5n%40googlegroups.com?utm_medium=email&utm_source=footer
 
-* use the same DicomMap as the core of Orthanc (wrt ExtraMainDicomTags)
-  from https://groups.google.com/g/orthanc-users/c/-ZKW9967DW4/m/9T3bwHeCAAAJ
-  command to test:
-  curl -H "Accept: application/json" http://localhost:8044/dicom-web/studies/1.2.840.113619.2.404.3.2831156996.875.1599094730.441/series/1.2.840.113619.2.404.3.2831156996.875.1599094730.453.5/metadata
-  -> return MainDicomSequences
-
-
-* handle same SeriesInstanceUID in different studies:
-  from https://groups.google.com/g/orthanc-users/c/nSBcMP_ri4o/m/sQxqKa72BAAJ
-  We can indeed solve the issue by calling tools/find instead of tools/lookup in the LocateSeries method
-
 * From Sylvain:
   curl http://localhost:8044/dicom-web/instances?StudyInstanceUID=1.2.3.4 shall return not only the instance tags but also the study level tags.
   See section 10.6.3.3.3 "Instance Resources" in https://dicom.nema.org/medical/dicom/current/output/html/part18.html: