# HG changeset patch # User Sebastien Jodogne # Date 1391615219 -3600 # Node ID dd1ce9a2844ce408b83074e4ed4ca19b890016ac # Parent 4c1860179cc509501022290e3f4c8779f547a7ee access to attachments diff -r 4c1860179cc5 -r dd1ce9a2844c Core/Enumerations.cpp --- 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; } diff -r 4c1860179cc5 -r dd1ce9a2844c Core/Enumerations.h --- 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, diff -r 4c1860179cc5 -r dd1ce9a2844c OrthancServer/OrthancRestApi.cpp --- 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 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 attachments; + context.GetIndex().ListAvailableAttachments(attachments, publicId, StringToResourceType(resourceType.c_str())); + + Json::Value result = Json::arrayValue; + + for (std::list::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 + 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(info.GetUncompressedSize()), "text/plain"); + } + } + + + static void GetAttachmentCompressedSize(RestApi::GetCall& call) + { + FileInfo info; + if (GetAttachmentInfo(info, call)) + { + call.GetOutput().AnswerBuffer(boost::lexical_cast(info.GetCompressedSize()), "text/plain"); + } + } + + + static void GetAttachmentMD5(RestApi::GetCall& call) + { + FileInfo info; + if (GetAttachmentInfo(info, call) && + info.GetUncompressedMD5() != "") + { + call.GetOutput().AnswerBuffer(boost::lexical_cast(info.GetUncompressedMD5()), "text/plain"); + } + } + + + static void GetAttachmentCompressedMD5(RestApi::GetCall& call) + { + FileInfo info; + if (GetAttachmentInfo(info, call) && + info.GetCompressedMD5() != "") + { + call.GetOutput().AnswerBuffer(boost::lexical_cast(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); diff -r 4c1860179cc5 -r dd1ce9a2844c OrthancServer/ServerContext.cpp --- 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()); } diff -r 4c1860179cc5 -r dd1ce9a2844c OrthancServer/ServerContext.h --- 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); diff -r 4c1860179cc5 -r dd1ce9a2844c OrthancServer/ServerEnumerations.cpp --- 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, diff -r 4c1860179cc5 -r dd1ce9a2844c OrthancServer/ServerIndex.cpp --- 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& 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) { diff -r 4c1860179cc5 -r dd1ce9a2844c OrthancServer/ServerIndex.h --- 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& target, const std::string& publicId); + void ListAvailableAttachments(std::list& target, + const std::string& publicId, + ResourceType expectedType); + bool LookupParent(std::string& target, const std::string& publicId); diff -r 4c1860179cc5 -r dd1ce9a2844c UnitTestsSources/ServerIndex.cpp --- 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(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());