changeset 697:dd1ce9a2844c

access to attachments
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 05 Feb 2014 16:46:59 +0100
parents 4c1860179cc5
children aae83e1e31f7
files Core/Enumerations.cpp Core/Enumerations.h OrthancServer/OrthancRestApi.cpp OrthancServer/ServerContext.cpp OrthancServer/ServerContext.h OrthancServer/ServerEnumerations.cpp OrthancServer/ServerIndex.cpp OrthancServer/ServerIndex.h UnitTestsSources/ServerIndex.cpp
diffstat 9 files changed, 208 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- a/Core/Enumerations.cpp	Wed Feb 05 15:00:29 2014 +0100
+++ b/Core/Enumerations.cpp	Wed Feb 05 16:46:59 2014 +0100
@@ -252,11 +252,11 @@
     std::string s(type);
     Toolbox::ToUpperCase(s);
 
-    if (s == "PATIENT")
+    if (s == "PATIENT" || s == "PATIENTS")
     {
       return ResourceType_Patient;
     }
-    else if (s == "STUDY")
+    else if (s == "STUDY" || s == "STUDIES")
     {
       return ResourceType_Study;
     }
@@ -264,7 +264,8 @@
     {
       return ResourceType_Series;
     }
-    else if (s == "INSTANCE" || s == "IMAGE")
+    else if (s == "INSTANCE"  || s == "IMAGE" || 
+             s == "INSTANCES" || s == "IMAGES")
     {
       return ResourceType_Instance;
     }
--- a/Core/Enumerations.h	Wed Feb 05 15:00:29 2014 +0100
+++ b/Core/Enumerations.h	Wed Feb 05 16:46:59 2014 +0100
@@ -226,7 +226,7 @@
   enum FileContentType
   {
     FileContentType_Dicom = 1,
-    FileContentType_JsonSummary = 2,
+    FileContentType_DicomAsJson = 2,
 
     // Make sure that the value "65535" can be stored into this enumeration
     FileContentType_StartUser = 1024,
--- a/OrthancServer/OrthancRestApi.cpp	Wed Feb 05 15:00:29 2014 +0100
+++ b/OrthancServer/OrthancRestApi.cpp	Wed Feb 05 16:46:59 2014 +0100
@@ -829,7 +829,7 @@
     RETRIEVE_CONTEXT(call);
 
     std::string publicId = call.GetUriComponent("id", "");
-    context.AnswerFile(call.GetOutput(), publicId, FileContentType_Dicom);
+    context.AnswerDicomFile(call.GetOutput(), publicId, FileContentType_Dicom);
   }
 
 
@@ -1654,9 +1654,17 @@
 
   // Handling of metadata -----------------------------------------------------
 
+  static void CheckValidResourceType(RestApi::Call& call)
+  {
+    std::string resourceType = call.GetUriComponent("resourceType", "");
+    StringToResourceType(resourceType.c_str());
+  }
+
+
   static void ListMetadata(RestApi::GetCall& call)
   {
     RETRIEVE_CONTEXT(call);
+    CheckValidResourceType(call);
     
     std::string publicId = call.GetUriComponent("id", "");
     std::list<MetadataType> metadata;
@@ -1678,6 +1686,7 @@
   static void GetMetadata(RestApi::GetCall& call)
   {
     RETRIEVE_CONTEXT(call);
+    CheckValidResourceType(call);
     
     std::string publicId = call.GetUriComponent("id", "");
     std::string name = call.GetUriComponent("name", "");
@@ -1694,7 +1703,8 @@
   static void DeleteMetadata(RestApi::DeleteCall& call)
   {
     RETRIEVE_CONTEXT(call);
-    
+    CheckValidResourceType(call);
+
     std::string publicId = call.GetUriComponent("id", "");
     std::string name = call.GetUriComponent("name", "");
     MetadataType metadata = StringToMetadata(name);
@@ -1712,6 +1722,7 @@
   static void SetMetadata(RestApi::PutCall& call)
   {
     RETRIEVE_CONTEXT(call);
+    CheckValidResourceType(call);
 
     std::string publicId = call.GetUriComponent("id", "");
     std::string name = call.GetUriComponent("name", "");
@@ -1822,6 +1833,137 @@
 
 
 
+
+  // Handling of attached files -----------------------------------------------
+
+  static void ListAttachments(RestApi::GetCall& call)
+  {
+    RETRIEVE_CONTEXT(call);
+    
+    std::string resourceType = call.GetUriComponent("resourceType", "");
+    std::string publicId = call.GetUriComponent("id", "");
+    std::list<FileContentType> attachments;
+    context.GetIndex().ListAvailableAttachments(attachments, publicId, StringToResourceType(resourceType.c_str()));
+
+    Json::Value result = Json::arrayValue;
+
+    for (std::list<FileContentType>::const_iterator 
+           it = attachments.begin(); it != attachments.end(); ++it)
+    {
+      result.append(EnumerationToString(*it));
+    }
+
+    call.GetOutput().AnswerJson(result);
+  }
+
+
+  static bool GetAttachmentInfo(FileInfo& info, RestApi::Call& call)
+  {
+    RETRIEVE_CONTEXT(call);
+    CheckValidResourceType(call);
+ 
+    std::string publicId = call.GetUriComponent("id", "");
+    std::string name = call.GetUriComponent("name", "");
+    FileContentType contentType = StringToContentType(name);
+
+    return context.GetIndex().LookupAttachment(info, publicId, contentType);
+  }
+
+
+  static void GetAttachmentOperations(RestApi::GetCall& call)
+  {
+    FileInfo info;
+    if (GetAttachmentInfo(info, call))
+    {
+      Json::Value operations = Json::arrayValue;
+
+      operations.append("compressed-data");
+
+      if (info.GetCompressedMD5() != "")
+      {
+        operations.append("compressed-md5");
+      }
+
+      operations.append("compressed-size");
+      operations.append("data");
+
+      if (info.GetUncompressedMD5() != "")
+      {
+        operations.append("md5");
+      }
+
+      operations.append("size");
+
+      if (info.GetCompressedMD5() != "")
+      {
+        operations.append("verify-md5");
+      }
+
+      call.GetOutput().AnswerJson(operations);
+    }
+  }
+
+  
+  template <int uncompress>
+  static void GetAttachmentData(RestApi::GetCall& call)
+  {
+    RETRIEVE_CONTEXT(call);
+    CheckValidResourceType(call);
+ 
+    std::string publicId = call.GetUriComponent("id", "");
+    std::string name = call.GetUriComponent("name", "");
+
+    std::string content;
+    context.ReadFile(content, publicId, StringToContentType(name),
+                     (uncompress == 1));
+
+    call.GetOutput().AnswerBuffer(content, "application/octet-stream");
+  }
+
+
+  static void GetAttachmentSize(RestApi::GetCall& call)
+  {
+    FileInfo info;
+    if (GetAttachmentInfo(info, call))
+    {
+      call.GetOutput().AnswerBuffer(boost::lexical_cast<std::string>(info.GetUncompressedSize()), "text/plain");
+    }
+  }
+
+
+  static void GetAttachmentCompressedSize(RestApi::GetCall& call)
+  {
+    FileInfo info;
+    if (GetAttachmentInfo(info, call))
+    {
+      call.GetOutput().AnswerBuffer(boost::lexical_cast<std::string>(info.GetCompressedSize()), "text/plain");
+    }
+  }
+
+
+  static void GetAttachmentMD5(RestApi::GetCall& call)
+  {
+    FileInfo info;
+    if (GetAttachmentInfo(info, call) &&
+        info.GetUncompressedMD5() != "")
+    {
+      call.GetOutput().AnswerBuffer(boost::lexical_cast<std::string>(info.GetUncompressedMD5()), "text/plain");
+    }
+  }
+
+
+  static void GetAttachmentCompressedMD5(RestApi::GetCall& call)
+  {
+    FileInfo info;
+    if (GetAttachmentInfo(info, call) &&
+        info.GetCompressedMD5() != "")
+    {
+      call.GetOutput().AnswerBuffer(boost::lexical_cast<std::string>(info.GetCompressedMD5()), "text/plain");
+    }
+  }
+
+
+
   // Registration of the various REST handlers --------------------------------
 
   OrthancRestApi::OrthancRestApi(ServerContext& context) : 
@@ -1862,22 +2004,19 @@
     Register("/studies/{id}/statistics", GetResourceStatistics);
     Register("/series/{id}/statistics", GetResourceStatistics);
 
-    Register("/instances/{id}/metadata", ListMetadata);
-    Register("/instances/{id}/metadata/{name}", DeleteMetadata);
-    Register("/instances/{id}/metadata/{name}", GetMetadata);
-    Register("/instances/{id}/metadata/{name}", SetMetadata);
-    Register("/patients/{id}/metadata", ListMetadata);
-    Register("/patients/{id}/metadata/{name}", DeleteMetadata);
-    Register("/patients/{id}/metadata/{name}", GetMetadata);
-    Register("/patients/{id}/metadata/{name}", SetMetadata);
-    Register("/series/{id}/metadata", ListMetadata);
-    Register("/series/{id}/metadata/{name}", DeleteMetadata);
-    Register("/series/{id}/metadata/{name}", GetMetadata);
-    Register("/series/{id}/metadata/{name}", SetMetadata);
-    Register("/studies/{id}/metadata", ListMetadata);
-    Register("/studies/{id}/metadata/{name}", DeleteMetadata);
-    Register("/studies/{id}/metadata/{name}", GetMetadata);
-    Register("/studies/{id}/metadata/{name}", SetMetadata);
+    Register("/{resourceType}/{id}/metadata", ListMetadata);
+    Register("/{resourceType}/{id}/metadata/{name}", DeleteMetadata);
+    Register("/{resourceType}/{id}/metadata/{name}", GetMetadata);
+    Register("/{resourceType}/{id}/metadata/{name}", SetMetadata);
+
+    Register("/{resourceType}/{id}/attachments", ListAttachments);
+    Register("/{resourceType}/{id}/attachments/{name}", GetAttachmentOperations);
+    Register("/{resourceType}/{id}/attachments/{name}/compressed-data", GetAttachmentData<0>);
+    Register("/{resourceType}/{id}/attachments/{name}/compressed-md5", GetAttachmentCompressedMD5);
+    Register("/{resourceType}/{id}/attachments/{name}/compressed-size", GetAttachmentCompressedSize);
+    Register("/{resourceType}/{id}/attachments/{name}/data", GetAttachmentData<1>);
+    Register("/{resourceType}/{id}/attachments/{name}/md5", GetAttachmentMD5);
+    Register("/{resourceType}/{id}/attachments/{name}/size", GetAttachmentSize);
 
     Register("/patients/{id}/protected", IsProtectedPatient);
     Register("/patients/{id}/protected", SetPatientProtection);
--- a/OrthancServer/ServerContext.cpp	Wed Feb 05 15:00:29 2014 +0100
+++ b/OrthancServer/ServerContext.cpp	Wed Feb 05 16:46:59 2014 +0100
@@ -116,7 +116,7 @@
     }      
 
     FileInfo dicomInfo = accessor_.Write(dicomInstance, dicomSize, FileContentType_Dicom);
-    FileInfo jsonInfo = accessor_.Write(dicomJson.toStyledString(), FileContentType_JsonSummary);
+    FileInfo jsonInfo = accessor_.Write(dicomJson.toStyledString(), FileContentType_DicomAsJson);
 
     ServerIndex::Attachments attachments;
     attachments.push_back(dicomInfo);
@@ -153,9 +153,9 @@
   }
 
   
-  void ServerContext::AnswerFile(RestApiOutput& output,
-                                 const std::string& instancePublicId,
-                                 FileContentType content)
+  void ServerContext::AnswerDicomFile(RestApiOutput& output,
+                                      const std::string& instancePublicId,
+                                      FileContentType content)
   {
     FileInfo attachment;
     if (!index_.LookupAttachment(attachment, instancePublicId, content))
@@ -176,7 +176,7 @@
                                const std::string& instancePublicId)
   {
     std::string s;
-    ReadFile(s, instancePublicId, FileContentType_JsonSummary);
+    ReadFile(s, instancePublicId, FileContentType_DicomAsJson);
 
     Json::Reader reader;
     if (!reader.parse(s, result))
@@ -188,7 +188,8 @@
 
   void ServerContext::ReadFile(std::string& result,
                                const std::string& instancePublicId,
-                               FileContentType content)
+                               FileContentType content,
+                               bool uncompressIfNeeded)
   {
     FileInfo attachment;
     if (!index_.LookupAttachment(attachment, instancePublicId, content))
@@ -196,7 +197,15 @@
       throw OrthancException(ErrorCode_InternalError);
     }
 
-    accessor_.SetCompressionForNextOperations(attachment.GetCompressionType());
+    if (uncompressIfNeeded)
+    {
+      accessor_.SetCompressionForNextOperations(attachment.GetCompressionType());
+    }
+    else
+    {
+      accessor_.SetCompressionForNextOperations(CompressionType_None);
+    }
+
     accessor_.Read(result, attachment.GetUuid());
   }
 
--- a/OrthancServer/ServerContext.h	Wed Feb 05 15:00:29 2014 +0100
+++ b/OrthancServer/ServerContext.h	Wed Feb 05 16:46:59 2014 +0100
@@ -118,9 +118,9 @@
         return Store(resultPublicId, &dicomContent[0], dicomContent.size());
     }
 
-    void AnswerFile(RestApiOutput& output,
-                    const std::string& instancePublicId,
-                    FileContentType content);
+    void AnswerDicomFile(RestApiOutput& output,
+                         const std::string& instancePublicId,
+                         FileContentType content);
 
     void ReadJson(Json::Value& result,
                   const std::string& instancePublicId);
@@ -128,7 +128,8 @@
     // TODO CACHING MECHANISM AT THIS POINT
     void ReadFile(std::string& result,
                   const std::string& instancePublicId,
-                  FileContentType content);
+                  FileContentType content,
+                  bool uncompressIfNeeded = true);
 
     // TODO IMPLEMENT MULTITHREADING FOR THIS METHOD
     ParsedDicomFile& GetDicomFile(const std::string& instancePublicId);
--- a/OrthancServer/ServerEnumerations.cpp	Wed Feb 05 15:00:29 2014 +0100
+++ b/OrthancServer/ServerEnumerations.cpp	Wed Feb 05 16:46:59 2014 +0100
@@ -56,7 +56,7 @@
     dictMetadataType_.Add(MetadataType_LastUpdate, "LastUpdate");
 
     dictContentType_.Add(FileContentType_Dicom, "dicom");
-    dictContentType_.Add(FileContentType_JsonSummary, "json-summary");
+    dictContentType_.Add(FileContentType_DicomAsJson, "dicom-as-json");
   }
 
   void RegisterUserMetadata(int metadata,
--- a/OrthancServer/ServerIndex.cpp	Wed Feb 05 15:00:29 2014 +0100
+++ b/OrthancServer/ServerIndex.cpp	Wed Feb 05 16:46:59 2014 +0100
@@ -1224,6 +1224,24 @@
   }
 
 
+  void ServerIndex::ListAvailableAttachments(std::list<FileContentType>& target,
+                                             const std::string& publicId,
+                                             ResourceType expectedType)
+  {
+    boost::mutex::scoped_lock lock(mutex_);
+
+    ResourceType type;
+    int64_t id;
+    if (!db_->LookupResource(publicId, id, type) ||
+        expectedType != type)
+    {
+      throw OrthancException(ErrorCode_UnknownResource);
+    }
+
+    db_->ListAvailableAttachments(target, id);
+  }
+
+
   bool ServerIndex::LookupParent(std::string& target,
                                  const std::string& publicId)
   {
--- a/OrthancServer/ServerIndex.h	Wed Feb 05 15:00:29 2014 +0100
+++ b/OrthancServer/ServerIndex.h	Wed Feb 05 16:46:59 2014 +0100
@@ -180,6 +180,10 @@
     bool ListAvailableMetadata(std::list<MetadataType>& target,
                                const std::string& publicId);
 
+    void ListAvailableAttachments(std::list<FileContentType>& target,
+                                  const std::string& publicId,
+                                  ResourceType expectedType);
+
     bool LookupParent(std::string& target,
                       const std::string& publicId);
 
--- a/UnitTestsSources/ServerIndex.cpp	Wed Feb 05 15:00:29 2014 +0100
+++ b/UnitTestsSources/ServerIndex.cpp	Wed Feb 05 16:46:59 2014 +0100
@@ -140,7 +140,7 @@
   index.ListAvailableMetadata(md, a[4]);
   ASSERT_EQ(0u, md.size());
 
-  index.AddAttachment(a[4], FileInfo("my json file", FileContentType_JsonSummary, 42, "md5", 
+  index.AddAttachment(a[4], FileInfo("my json file", FileContentType_DicomAsJson, 42, "md5", 
                                      CompressionType_Zlib, 21, "compressedMD5"));
   index.AddAttachment(a[4], FileInfo("my dicom file", FileContentType_Dicom, 42, "md5"));
   index.AddAttachment(a[6], FileInfo("world", FileContentType_Dicom, 44, "md5"));
@@ -183,7 +183,7 @@
   ASSERT_EQ("None", index.GetGlobalProperty(static_cast<GlobalProperty>(42), "None"));
 
   FileInfo att;
-  ASSERT_TRUE(index.LookupAttachment(att, a[4], FileContentType_JsonSummary));
+  ASSERT_TRUE(index.LookupAttachment(att, a[4], FileContentType_DicomAsJson));
   ASSERT_EQ("my json file", att.GetUuid());
   ASSERT_EQ(21u, att.GetCompressedSize());
   ASSERT_EQ("md5", att.GetUncompressedMD5());