Mercurial > hg > orthanc
changeset 5710:a786da7599d5 find-refactoring-clean
integration find-refactoring->find-refactoring-clean
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 12 Jul 2024 18:55:22 +0200 |
parents | c8d21a09aae6 (diff) 476b1db52110 (current diff) |
children | 31eb66eaed86 |
files | OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp OrthancServer/Sources/OrthancWebDav.cpp |
diffstat | 6 files changed, 100 insertions(+), 1251 deletions(-) [+] |
line wrap: on
line diff
--- a/OrthancServer/Sources/OrthancFindRequestHandler.cpp Fri Jul 12 18:41:44 2024 +0200 +++ b/OrthancServer/Sources/OrthancFindRequestHandler.cpp Fri Jul 12 18:55:22 2024 +0200 @@ -82,102 +82,6 @@ } - static void AddAnswer(DicomFindAnswers& answers, - ServerContext& context, - const std::string& publicId, - const std::string& instanceId, - const DicomMap& mainDicomTags, - const Json::Value* dicomAsJson, - ResourceType level, - const DicomArray& query, - const std::list<DicomTag>& sequencesToReturn, - const std::string& defaultPrivateCreator, - const std::map<uint16_t, std::string>& privateCreators, - const std::string& retrieveAet, - bool allowStorageAccess) - { - ExpandedResource resource; - std::set<DicomTag> requestedTags; - - query.GetTags(requestedTags); - requestedTags.erase(DICOM_TAG_QUERY_RETRIEVE_LEVEL); // this is not part of the answer - - // reuse ExpandResource to get missing tags and computed tags (ModalitiesInStudy ...). This code is therefore shared between C-Find, tools/find, list-resources and QIDO-RS - context.ExpandResource(resource, publicId, mainDicomTags, instanceId, dicomAsJson, - level, requestedTags, ExpandResourceFlags_IncludeMainDicomTags, allowStorageAccess); - - DicomMap result; - - /** - * Add the mandatory "Retrieve AE Title (0008,0054)" tag, which was missing in Orthanc <= 1.7.2. - * http://dicom.nema.org/medical/dicom/current/output/html/part04.html#sect_C.4.1.1.3.2 - * https://groups.google.com/g/orthanc-users/c/-7zNTKR_PMU/m/kfjwzEVNAgAJ - **/ - result.SetValue(DICOM_TAG_RETRIEVE_AE_TITLE, retrieveAet, false /* not binary */); - - for (size_t i = 0; i < query.GetSize(); i++) - { - if (query.GetElement(i).GetTag() == DICOM_TAG_QUERY_RETRIEVE_LEVEL) - { - // Fix issue 30 on Google Code (QR response missing "Query/Retrieve Level" (008,0052)) - result.SetValue(query.GetElement(i).GetTag(), query.GetElement(i).GetValue()); - } - else if (query.GetElement(i).GetTag() == DICOM_TAG_SPECIFIC_CHARACTER_SET) - { - // Do not include the encoding, this is handled by class ParsedDicomFile - } - else - { - const DicomTag& tag = query.GetElement(i).GetTag(); - const DicomValue* value = resource.GetMainDicomTags().TestAndGetValue(tag); - - if (value != NULL && - !value->IsNull() && - !value->IsBinary()) - { - result.SetValue(tag, value->GetContent(), false); - } - else - { - result.SetValue(tag, "", false); - } - } - } - - if (result.GetSize() == 0 && - sequencesToReturn.empty()) - { - CLOG(WARNING, DICOM) << "The C-FIND request does not return any DICOM tag"; - } - else if (sequencesToReturn.empty()) - { - answers.Add(result); - } - else if (dicomAsJson == NULL) - { - CLOG(WARNING, DICOM) << "C-FIND query requesting a sequence, but reading JSON from disk is disabled"; - answers.Add(result); - } - else - { - ParsedDicomFile dicom(result, GetDefaultDicomEncoding(), - true /* be permissive, cf. issue #136 */, defaultPrivateCreator, privateCreators); - - for (std::list<DicomTag>::const_iterator tag = sequencesToReturn.begin(); - tag != sequencesToReturn.end(); ++tag) - { - assert(dicomAsJson != NULL); - const Json::Value& source = (*dicomAsJson) [tag->Format()]; - - CopySequence(dicom, *tag, source, defaultPrivateCreator, privateCreators); - } - - answers.Add(dicom); - } - } - - - bool OrthancFindRequestHandler::FilterQueryTag(std::string& value /* can be modified */, ResourceType level, const DicomTag& tag, @@ -248,88 +152,6 @@ } - class OrthancFindRequestHandler::LookupVisitor : public ServerContext::ILookupVisitor - { - private: - DicomFindAnswers& answers_; - ServerContext& context_; - ResourceType level_; - const DicomMap& query_; - DicomArray queryAsArray_; - const std::list<DicomTag>& sequencesToReturn_; - std::string defaultPrivateCreator_; // the private creator to use if the group is not defined in the query itself - const std::map<uint16_t, std::string>& privateCreators_; // the private creators defined in the query itself - std::string retrieveAet_; - FindStorageAccessMode findStorageAccessMode_; - - public: - LookupVisitor(DicomFindAnswers& answers, - ServerContext& context, - ResourceType level, - const DicomMap& query, - const std::list<DicomTag>& sequencesToReturn, - const std::map<uint16_t, std::string>& privateCreators, - FindStorageAccessMode findStorageAccessMode) : - answers_(answers), - context_(context), - level_(level), - query_(query), - queryAsArray_(query), - sequencesToReturn_(sequencesToReturn), - privateCreators_(privateCreators), - findStorageAccessMode_(findStorageAccessMode) - { - answers_.SetComplete(false); - - { - OrthancConfiguration::ReaderLock lock; - defaultPrivateCreator_ = lock.GetConfiguration().GetDefaultPrivateCreator(); - retrieveAet_ = lock.GetConfiguration().GetOrthancAET(); - } - } - - virtual bool IsDicomAsJsonNeeded() const ORTHANC_OVERRIDE - { - // Ask the "DICOM-as-JSON" attachment only if sequences are to - // be returned OR if "query_" contains non-main DICOM tags! - - DicomMap withoutSpecialTags; - withoutSpecialTags.Assign(query_); - - // Check out "ComputeCounters()" - withoutSpecialTags.Remove(DICOM_TAG_MODALITIES_IN_STUDY); - withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES); - withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES); - withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES); - withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES); - withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES); - withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES); - withoutSpecialTags.Remove(DICOM_TAG_SOP_CLASSES_IN_STUDY); - - // Check out "AddAnswer()" - withoutSpecialTags.Remove(DICOM_TAG_SPECIFIC_CHARACTER_SET); - withoutSpecialTags.Remove(DICOM_TAG_QUERY_RETRIEVE_LEVEL); - - return (!sequencesToReturn_.empty() || - !withoutSpecialTags.HasOnlyMainDicomTags()); - } - - virtual void MarkAsComplete() ORTHANC_OVERRIDE - { - answers_.SetComplete(true); - } - - virtual void Visit(const std::string& publicId, - const std::string& instanceId, - const DicomMap& mainDicomTags, - const Json::Value* dicomAsJson) ORTHANC_OVERRIDE - { - AddAnswer(answers_, context_, publicId, instanceId, mainDicomTags, dicomAsJson, level_, queryAsArray_, sequencesToReturn_, - defaultPrivateCreator_, privateCreators_, retrieveAet_, IsStorageAccessAllowedForAnswers(findStorageAccessMode_)); - } - }; - - namespace { class LookupVisitorV2 : public ResourceFinder::IVisitor @@ -622,31 +444,12 @@ * Run the query. **/ - size_t limit = (level == ResourceType_Instance) ? maxInstances_ : maxResults_; - - - if (true) - { - /** - * EXPERIMENTAL VERSION - **/ - - ResourceFinder finder(level, false /* don't expand */); - finder.SetDatabaseLookup(lookup); - finder.AddRequestedTags(requestedTags); + ResourceFinder finder(level, false /* don't expand */); + finder.SetDatabaseLookup(lookup); + finder.AddRequestedTags(requestedTags); - LookupVisitorV2 visitor(answers, *filteredInput, sequencesToReturn, privateCreators); - finder.Execute(visitor, context_); - } - else - { - /** - * VERSION IN ORTHANC <= 1.12.4 - **/ - - LookupVisitor visitor(answers, context_, level, *filteredInput, sequencesToReturn, privateCreators, context_.GetFindStorageAccessMode()); - context_.Apply(visitor, lookup, level, 0 /* "since" is not relevant to C-FIND */, limit); - } + LookupVisitorV2 visitor(answers, *filteredInput, sequencesToReturn, privateCreators); + finder.Execute(visitor, context_); }
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp Fri Jul 12 18:41:44 2024 +0200 +++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp Fri Jul 12 18:55:22 2024 +0200 @@ -174,77 +174,6 @@ // List all the patients, studies, series or instances ---------------------- - static void AnswerListOfResources1(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, boost::shared_ptr<Json::Value> >& resourcesDicomAsJson, // optional: the dicom-as-json for each resource - ResourceType level, - bool expand, - DicomToJsonFormat format, - const std::set<DicomTag>& requestedTags, - bool allowStorageAccess) - { - Json::Value answer = Json::arrayValue; - - for (std::list<std::string>::const_iterator - resource = resources.begin(); resource != resources.end(); ++resource) - { - if (expand) - { - Json::Value expanded; - - std::map<std::string, std::string>::const_iterator instanceId = instancesIds.find(*resource); - if (instanceId != instancesIds.end()) // if it is found in instancesIds, it is also in resourcesDicomAsJson and mainDicomTags - { - // reuse data already collected before (e.g during lookup) - std::map<std::string, boost::shared_ptr<DicomMap> >::const_iterator mainDicomTags = resourcesMainDicomTags.find(*resource); - std::map<std::string, boost::shared_ptr<Json::Value> >::const_iterator dicomAsJson = resourcesDicomAsJson.find(*resource); - - context.ExpandResource(expanded, *resource, - *(mainDicomTags->second.get()), - instanceId->second, - dicomAsJson->second.get(), - level, format, requestedTags, allowStorageAccess); - } - else - { - context.ExpandResource(expanded, *resource, level, format, requestedTags, allowStorageAccess); - } - - if (expanded.type() == Json::objectValue) - { - answer.append(expanded); - } - } - else - { - answer.append(*resource); - } - } - - output.AnswerJson(answer); - } - - - static void AnswerListOfResources2(RestApiOutput& output, - ServerContext& context, - const std::list<std::string>& resources, - ResourceType level, - bool expand, - DicomToJsonFormat format, - const std::set<DicomTag>& requestedTags, - bool allowStorageAccess) - { - std::map<std::string, std::string> unusedInstancesIds; - std::map<std::string, boost::shared_ptr<DicomMap> > unusedResourcesMainDicomTags; - std::map<std::string, boost::shared_ptr<Json::Value> > unusedResourcesDicomAsJson; - - AnswerListOfResources1(output, context, resources, unusedInstancesIds, unusedResourcesMainDicomTags, unusedResourcesDicomAsJson, level, expand, format, requestedTags, allowStorageAccess); - } - - template <enum ResourceType resourceType> static void ListResources(RestApiGetCall& call) { @@ -267,96 +196,44 @@ .SetHttpGetSample("https://orthanc.uclouvain.be/demo/" + resources + "?since=0&limit=2", true); return; } - - ServerIndex& index = OrthancRestApi::GetIndex(call); - ServerContext& context = OrthancRestApi::GetContext(call); - - if (true) + + // TODO-FIND: include the FindRequest options parsing in a method (parse from get-arguments and from post payload) + // TODO-FIND: support other values for expand like expand=MainDicomTags,Labels,Parent,SeriesStatus + const bool expand = (call.HasArgument("expand") && + call.GetBooleanArgument("expand", true)); + + std::set<DicomTag> requestedTags; + OrthancRestApi::GetRequestedTags(requestedTags, call); + + ResourceFinder finder(resourceType, expand); + finder.AddRequestedTags(requestedTags); + + if (call.HasArgument("limit") || + call.HasArgument("since")) { - /** - * EXPERIMENTAL VERSION - **/ - - // TODO-FIND: include the FindRequest options parsing in a method (parse from get-arguments and from post payload) - // TODO-FIND: support other values for expand like expand=MainDicomTags,Labels,Parent,SeriesStatus - const bool expand = (call.HasArgument("expand") && - call.GetBooleanArgument("expand", true)); - - std::set<DicomTag> requestedTags; - OrthancRestApi::GetRequestedTags(requestedTags, call); - - ResourceFinder finder(resourceType, expand); - finder.AddRequestedTags(requestedTags); - - if (call.HasArgument("limit") || - call.HasArgument("since")) + if (!call.HasArgument("limit")) { - if (!call.HasArgument("limit")) - { - throw OrthancException(ErrorCode_BadRequest, - "Missing \"limit\" argument for GET request against: " + - call.FlattenUri()); - } - - if (!call.HasArgument("since")) - { - throw OrthancException(ErrorCode_BadRequest, - "Missing \"since\" argument for GET request against: " + - call.FlattenUri()); - } - - uint64_t since = boost::lexical_cast<uint64_t>(call.GetArgument("since", "")); - uint64_t limit = boost::lexical_cast<uint64_t>(call.GetArgument("limit", "")); - finder.SetLimitsSince(since); - finder.SetLimitsCount(limit); + throw OrthancException(ErrorCode_BadRequest, + "Missing \"limit\" argument for GET request against: " + + call.FlattenUri()); } - Json::Value answer; - finder.Execute(answer, context, OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human)); - call.GetOutput().AnswerJson(answer); - } - else - { - /** - * VERSION IN ORTHANC <= 1.12.4 - **/ - - std::list<std::string> result; - - std::set<DicomTag> requestedTags; - OrthancRestApi::GetRequestedTags(requestedTags, call); - - if (call.HasArgument("limit") || - call.HasArgument("since")) + if (!call.HasArgument("since")) { - if (!call.HasArgument("limit")) - { - throw OrthancException(ErrorCode_BadRequest, - "Missing \"limit\" argument for GET request against: " + - call.FlattenUri()); - } - - if (!call.HasArgument("since")) - { - throw OrthancException(ErrorCode_BadRequest, - "Missing \"since\" argument for GET request against: " + - call.FlattenUri()); - } - - size_t since = boost::lexical_cast<size_t>(call.GetArgument("since", "")); - size_t limit = boost::lexical_cast<size_t>(call.GetArgument("limit", "")); - index.GetAllUuids(result, resourceType, since, limit); + throw OrthancException(ErrorCode_BadRequest, + "Missing \"since\" argument for GET request against: " + + call.FlattenUri()); } - else - { - index.GetAllUuids(result, resourceType); - } - - AnswerListOfResources2(call.GetOutput(), context, result, resourceType, call.HasArgument("expand") && call.GetBooleanArgument("expand", true), - OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human), - requestedTags, - true /* allowStorageAccess */); + + uint64_t since = boost::lexical_cast<uint64_t>(call.GetArgument("since", "")); + uint64_t limit = boost::lexical_cast<uint64_t>(call.GetArgument("limit", "")); + finder.SetLimitsSince(since); + finder.SetLimitsCount(limit); } + + Json::Value answer; + finder.Execute(answer, OrthancRestApi::GetContext(call), OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human)); + call.GetOutput().AnswerJson(answer); } @@ -380,39 +257,19 @@ return; } - const DicomToJsonFormat format = OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human); - std::set<DicomTag> requestedTags; OrthancRestApi::GetRequestedTags(requestedTags, call); - if (true) + const DicomToJsonFormat format = OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human); + + ResourceFinder finder(resourceType, true /* expand */); + finder.AddRequestedTags(requestedTags); + finder.SetOrthancId(resourceType, call.GetUriComponent("id", "")); + + Json::Value json; + if (finder.ExecuteOneResource(json, OrthancRestApi::GetContext(call), format)) { - /** - * EXPERIMENTAL VERSION - **/ - - ResourceFinder finder(resourceType, true /* expand */); - finder.AddRequestedTags(requestedTags); - finder.SetOrthancId(resourceType, call.GetUriComponent("id", "")); - - Json::Value json; - if (finder.ExecuteOneResource(json, OrthancRestApi::GetContext(call), format)) - { - call.GetOutput().AnswerJson(json); - } - } - else - { - /** - * VERSION IN ORTHANC <= 1.12.4 - **/ - - Json::Value json; - if (OrthancRestApi::GetContext(call).ExpandResource( - json, call.GetUriComponent("id", ""), resourceType, format, requestedTags, true /* allowStorageAccess */)) - { - call.GetOutput().AnswerJson(json); - } + call.GetOutput().AnswerJson(json); } } @@ -3201,70 +3058,6 @@ } - namespace - { - class FindVisitor : public ServerContext::ILookupVisitor - { - private: - bool isComplete_; - std::list<std::string> resources_; - FindStorageAccessMode findStorageAccessMode_; - - // 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, boost::shared_ptr<Json::Value> > resourcesDicomAsJson_; // the dicom-as-json for a resource - - DicomToJsonFormat format_; - - public: - explicit FindVisitor(DicomToJsonFormat format, FindStorageAccessMode findStorageAccessMode) : - isComplete_(false), - findStorageAccessMode_(findStorageAccessMode), - format_(format) - { - } - - virtual bool IsDicomAsJsonNeeded() const ORTHANC_OVERRIDE - { - return false; // (*) - } - - virtual void MarkAsComplete() ORTHANC_OVERRIDE - { - isComplete_ = true; // Unused information as of Orthanc 1.5.0 - } - - virtual void Visit(const std::string& publicId, - 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()); - if (dicomAsJson != NULL) - { - resourcesDicomAsJson_[publicId].reset(new Json::Value(*dicomAsJson)); // keep our own copy because we might reuse it between lookup and answers - } - else - { - resourcesDicomAsJson_[publicId] = boost::shared_ptr<Json::Value>(); - } - } - - void Answer(RestApiOutput& output, - ServerContext& context, - ResourceType level, - bool expand, - const std::set<DicomTag>& requestedTags) const - { - AnswerListOfResources1(output, context, resources_, instancesIds_, resourcesMainDicomTags_, resourcesDicomAsJson_, level, expand, format_, requestedTags, IsStorageAccessAllowedForAnswers(findStorageAccessMode_)); - } - }; - } - - static void Find(RestApiPostCall& call) { static const char* const KEY_CASE_SENSITIVE = "CaseSensitive"; @@ -3371,12 +3164,8 @@ throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_LABELS_CONSTRAINT) + "\" must be an array of strings"); } - else if (true) + else { - /** - * EXPERIMENTAL VERSION - **/ - bool expand = false; if (request.isMember(KEY_EXPAND)) { @@ -3500,125 +3289,6 @@ finder.Execute(answer, context, format); call.GetOutput().AnswerJson(answer); } - else - { - /** - * VERSION IN ORTHANC <= 1.12.4 - **/ - bool expand = false; - if (request.isMember(KEY_EXPAND)) - { - expand = request[KEY_EXPAND].asBool(); - } - - bool caseSensitive = false; - if (request.isMember(KEY_CASE_SENSITIVE)) - { - caseSensitive = request[KEY_CASE_SENSITIVE].asBool(); - } - - size_t limit = 0; - if (request.isMember(KEY_LIMIT)) - { - int tmp = request[KEY_LIMIT].asInt(); - if (tmp < 0) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Field \"" + std::string(KEY_LIMIT) + "\" must be a positive integer"); - } - - limit = static_cast<size_t>(tmp); - } - - size_t since = 0; - if (request.isMember(KEY_SINCE)) - { - int tmp = request[KEY_SINCE].asInt(); - if (tmp < 0) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Field \"" + std::string(KEY_SINCE) + "\" must be a positive integer"); - } - - since = static_cast<size_t>(tmp); - } - - std::set<DicomTag> requestedTags; - - if (request.isMember(KEY_REQUESTED_TAGS)) - { - FromDcmtkBridge::ParseListOfTags(requestedTags, request[KEY_REQUESTED_TAGS]); - } - - ResourceType level = StringToResourceType(request[KEY_LEVEL].asCString()); - - DatabaseLookup query; - - Json::Value::Members members = request[KEY_QUERY].getMemberNames(); - for (size_t i = 0; i < members.size(); i++) - { - if (request[KEY_QUERY][members[i]].type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadRequest, - "Tag \"" + members[i] + "\" must be associated with a string"); - } - - const std::string value = request[KEY_QUERY][members[i]].asString(); - - if (!value.empty()) - { - // An empty string corresponds to an universal constraint, - // so we ignore it. This mimics the behavior of class - // "OrthancFindRequestHandler" - query.AddRestConstraint(FromDcmtkBridge::ParseTag(members[i]), - value, caseSensitive, true); - } - } - - std::set<std::string> labels; - - if (request.isMember(KEY_LABELS)) // New in Orthanc 1.12.0 - { - for (Json::Value::ArrayIndex i = 0; i < request[KEY_LABELS].size(); i++) - { - if (request[KEY_LABELS][i].type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_LABELS) + "\" must contain strings"); - } - else - { - labels.insert(request[KEY_LABELS][i].asString()); - } - } - } - - LabelsConstraint labelsConstraint = LabelsConstraint_All; - - if (request.isMember(KEY_LABELS_CONSTRAINT)) - { - const std::string& s = request[KEY_LABELS_CONSTRAINT].asString(); - if (s == "All") - { - labelsConstraint = LabelsConstraint_All; - } - else if (s == "Any") - { - labelsConstraint = LabelsConstraint_Any; - } - else if (s == "None") - { - labelsConstraint = LabelsConstraint_None; - } - else - { - throw OrthancException(ErrorCode_BadRequest, "Field \"" + std::string(KEY_LABELS_CONSTRAINT) + "\" must be \"All\", \"Any\", or \"None\""); - } - } - - FindVisitor visitor(OrthancRestApi::GetDicomFormat(request, DicomToJsonFormat_Human), context.GetFindStorageAccessMode()); - context.Apply(visitor, query, level, labels, labelsConstraint, since, limit); - visitor.Answer(call.GetOutput(), context, level, expand, requestedTags); - } } @@ -3646,9 +3316,6 @@ return; } - ServerIndex& index = OrthancRestApi::GetIndex(call); - ServerContext& context = OrthancRestApi::GetContext(call); - const bool expand = (!call.HasArgument("expand") || // this "expand" is the only one to have a false default value to keep backward compatibility call.GetBooleanArgument("expand", false)); @@ -3657,48 +3324,13 @@ std::set<DicomTag> requestedTags; OrthancRestApi::GetRequestedTags(requestedTags, call); - if (true) - { - /** - * EXPERIMENTAL VERSION - **/ - - ResourceFinder finder(end, expand); - finder.SetOrthancId(start, call.GetUriComponent("id", "")); - finder.AddRequestedTags(requestedTags); - - Json::Value answer; - finder.Execute(answer, context, format); - call.GetOutput().AnswerJson(answer); - } - else - { - /** - * VERSION IN ORTHANC <= 1.12.4 - **/ - std::list<std::string> a, b, c; - a.push_back(call.GetUriComponent("id", "")); - - ResourceType type = start; - while (type != end) - { - b.clear(); - - for (std::list<std::string>::const_iterator - it = a.begin(); it != a.end(); ++it) - { - index.GetChildren(c, *it); - b.splice(b.begin(), c); - } - - type = GetChildResourceType(type); - - a.clear(); - a.splice(a.begin(), b); - } - - AnswerListOfResources2(call.GetOutput(), context, a, type, expand, format, requestedTags, true /* allowStorageAccess */); - } + ResourceFinder finder(end, expand); + finder.SetOrthancId(start, call.GetUriComponent("id", "")); + finder.AddRequestedTags(requestedTags); + + Json::Value answer; + finder.Execute(answer, OrthancRestApi::GetContext(call), format); + call.GetOutput().AnswerJson(answer); } @@ -3811,26 +3443,9 @@ const DicomToJsonFormat format = OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human); Json::Value resource; - - if (true) + if (OrthancRestApi::GetContext(call).ExpandResource(resource, current, end, format, requestedTags, true /* allowStorageAccess */)) { - /** - * EXPERIMENTAL VERSION - **/ - if (ExpandResource(resource, OrthancRestApi::GetIndex(call), currentType, current, format, false)) - { - call.GetOutput().AnswerJson(resource); - } - } - else - { - /** - * VERSION IN ORTHANC <= 1.12.4 - **/ - if (OrthancRestApi::GetContext(call).ExpandResource(resource, current, end, format, requestedTags, true /* allowStorageAccess */)) - { - call.GetOutput().AnswerJson(resource); - } + call.GetOutput().AnswerJson(resource); } } @@ -4261,34 +3876,17 @@ for (std::set<std::string>::const_iterator it = interest.begin(); it != interest.end(); ++it) { - if (true) - { - /** - * EXPERIMENTAL VERSION - **/ - Json::Value item; - if (ExpandResource(item, OrthancRestApi::GetIndex(call), level, *it, format, metadata)) - { - answer.append(item); - } - } - else + Json::Value item; + std::set<DicomTag> emptyRequestedTags; // not supported for bulk content + + if (OrthancRestApi::GetContext(call).ExpandResource(item, *it, level, format, emptyRequestedTags, true /* allowStorageAccess */)) { - /** - * VERSION IN ORTHANC <= 1.12.4 - **/ - Json::Value item; - std::set<DicomTag> emptyRequestedTags; // not supported for bulk content - - if (OrthancRestApi::GetContext(call).ExpandResource(item, *it, level, format, emptyRequestedTags, true /* allowStorageAccess */)) + if (metadata) { - if (metadata) - { - AddMetadata(item[METADATA], index, *it, level); - } - - answer.append(item); + AddMetadata(item[METADATA], index, *it, level); } + + answer.append(item); } } } @@ -4305,36 +3903,19 @@ Json::Value item; std::set<DicomTag> emptyRequestedTags; // not supported for bulk content - if (true) + if (index.LookupResourceType(level, *it) && + OrthancRestApi::GetContext(call).ExpandResource(item, *it, level, format, emptyRequestedTags, true /* allowStorageAccess */)) { - /** - * EXPERIMENTAL VERSION - **/ - if (index.LookupResourceType(level, *it) && - ExpandResource(item, OrthancRestApi::GetIndex(call), level, *it, format, metadata)) + if (metadata) { - answer.append(item); + AddMetadata(item[METADATA], index, *it, level); } + + answer.append(item); } else { - /** - * VERSION IN ORTHANC <= 1.12.4 - **/ - if (index.LookupResourceType(level, *it) && - OrthancRestApi::GetContext(call).ExpandResource(item, *it, level, format, emptyRequestedTags, true /* allowStorageAccess */)) - { - if (metadata) - { - AddMetadata(item[METADATA], index, *it, level); - } - - answer.append(item); - } - else - { - CLOG(INFO, HTTP) << "Unknown resource during a bulk content retrieval: " << *it; - } + CLOG(INFO, HTTP) << "Unknown resource during a bulk content retrieval: " << *it; } } }
--- a/OrthancServer/Sources/OrthancWebDav.cpp Fri Jul 12 18:41:44 2024 +0200 +++ b/OrthancServer/Sources/OrthancWebDav.cpp Fri Jul 12 18:55:22 2024 +0200 @@ -86,99 +86,6 @@ } - class OrthancWebDav::DicomIdentifiersVisitor : public ServerContext::ILookupVisitor - { - private: - ServerContext& context_; - bool isComplete_; - Collection& target_; - ResourceType level_; - - public: - DicomIdentifiersVisitor(ServerContext& context, - Collection& target, - ResourceType level) : - context_(context), - isComplete_(false), - target_(target), - level_(level) - { - } - - virtual bool IsDicomAsJsonNeeded() const ORTHANC_OVERRIDE - { - return false; // (*) - } - - virtual void MarkAsComplete() ORTHANC_OVERRIDE - { - isComplete_ = true; // TODO - } - - virtual void Visit(const std::string& publicId, - const std::string& instanceId /* unused */, - const DicomMap& mainDicomTags, - const Json::Value* dicomAsJson /* unused (*) */) ORTHANC_OVERRIDE - { - DicomTag tag(0, 0); - MetadataType timeMetadata; - - switch (level_) - { - case ResourceType_Study: - tag = DICOM_TAG_STUDY_INSTANCE_UID; - timeMetadata = MetadataType_LastUpdate; - break; - - case ResourceType_Series: - tag = DICOM_TAG_SERIES_INSTANCE_UID; - timeMetadata = MetadataType_LastUpdate; - break; - - case ResourceType_Instance: - tag = DICOM_TAG_SOP_INSTANCE_UID; - timeMetadata = MetadataType_Instance_ReceptionDate; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - std::string s; - if (mainDicomTags.LookupStringValue(s, tag, false) && - !s.empty()) - { - std::unique_ptr<Resource> resource; - - if (level_ == ResourceType_Instance) - { - FileInfo info; - int64_t revision; // Ignored - if (context_.GetIndex().LookupAttachment(info, revision, publicId, FileContentType_Dicom)) - { - std::unique_ptr<File> f(new File(s + ".dcm")); - f->SetMimeType(MimeType_Dicom); - f->SetContentLength(info.GetUncompressedSize()); - resource.reset(f.release()); - } - } - else - { - resource.reset(new Folder(s)); - } - - if (resource.get() != NULL) - { - boost::posix_time::ptime t; - LookupTime(t, context_, publicId, level_, timeMetadata); - resource->SetCreationTime(t); - target_.AddResource(resource.release()); - } - } - } - }; - - class OrthancWebDav::DicomIdentifiersVisitorV2 : public ResourceFinder::IVisitor { private: @@ -271,58 +178,6 @@ }; - class OrthancWebDav::DicomFileVisitor : public ServerContext::ILookupVisitor - { - private: - ServerContext& context_; - bool success_; - std::string& target_; - boost::posix_time::ptime& time_; - - public: - DicomFileVisitor(ServerContext& context, - std::string& target, - boost::posix_time::ptime& time) : - context_(context), - success_(false), - target_(target), - time_(time) - { - } - - bool IsSuccess() const - { - return success_; - } - - virtual bool IsDicomAsJsonNeeded() const ORTHANC_OVERRIDE - { - return false; // (*) - } - - virtual void MarkAsComplete() ORTHANC_OVERRIDE - { - } - - virtual void Visit(const std::string& publicId, - const std::string& instanceId /* unused */, - const DicomMap& mainDicomTags, - const Json::Value* dicomAsJson /* unused (*) */) ORTHANC_OVERRIDE - { - if (success_) - { - success_ = false; // Two matches => Error - } - else - { - LookupTime(time_, context_, publicId, ResourceType_Instance, MetadataType_Instance_ReceptionDate); - context_.ReadDicom(target_, publicId); - success_ = true; - } - } - }; - - class OrthancWebDav::DicomFileVisitorV2 : public ResourceFinder::IVisitor { private: @@ -377,67 +232,6 @@ }; - class OrthancWebDav::OrthancJsonVisitor : public ServerContext::ILookupVisitor - { - private: - ServerContext& context_; - bool success_; - std::string& target_; - ResourceType level_; - - public: - OrthancJsonVisitor(ServerContext& context, - std::string& target, - ResourceType level) : - context_(context), - success_(false), - target_(target), - level_(level) - { - } - - bool IsSuccess() const - { - return success_; - } - - virtual bool IsDicomAsJsonNeeded() const ORTHANC_OVERRIDE - { - return false; // (*) - } - - virtual void MarkAsComplete() ORTHANC_OVERRIDE - { - } - - virtual void Visit(const std::string& publicId, - const std::string& instanceId /* unused */, - const DicomMap& mainDicomTags, - const Json::Value* dicomAsJson /* unused (*) */) ORTHANC_OVERRIDE - { - Json::Value resource; - std::set<DicomTag> emptyRequestedTags; // not supported for webdav - - if (context_.ExpandResource(resource, publicId, level_, DicomToJsonFormat_Human, emptyRequestedTags, true /* allowStorageAccess */)) - { - if (success_) - { - success_ = false; // Two matches => Error - } - else - { - target_ = resource.toStyledString(); - - // Replace UNIX newlines with DOS newlines - boost::replace_all(target_, "\n", "\r\n"); - - success_ = true; - } - } - } - }; - - class OrthancWebDav::ResourcesIndex : public boost::noncopyable { public: @@ -1569,12 +1363,11 @@ { DatabaseLookup query; ResourceType level; - size_t limit = 0; // By default, no limits if (path.size() == 1) { level = ResourceType_Study; - limit = 0; // TODO - Should we limit here? + // TODO - Should we limit here? } else if (path.size() == 2) { @@ -1599,47 +1392,31 @@ return false; } - if (true) - { - /** - * EXPERIMENTAL VERSION - **/ - - ResourceFinder finder(level, false /* don't expand */); - finder.SetDatabaseLookup(query); - finder.SetRetrieveMetadata(true); + ResourceFinder finder(level, false /* don't expand */); + finder.SetDatabaseLookup(query); + finder.SetRetrieveMetadata(true); - switch (level) - { - case ResourceType_Study: - finder.AddRequestedTag(DICOM_TAG_STUDY_INSTANCE_UID); - break; - - case ResourceType_Series: - finder.AddRequestedTag(DICOM_TAG_SERIES_INSTANCE_UID); - break; + switch (level) + { + case ResourceType_Study: + finder.AddRequestedTag(DICOM_TAG_STUDY_INSTANCE_UID); + break; - case ResourceType_Instance: - finder.AddRequestedTag(DICOM_TAG_SOP_INSTANCE_UID); - finder.SetRetrieveAttachments(true); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } + case ResourceType_Series: + finder.AddRequestedTag(DICOM_TAG_SERIES_INSTANCE_UID); + break; - DicomIdentifiersVisitorV2 visitor(collection); - finder.Execute(visitor, context_); + case ResourceType_Instance: + finder.AddRequestedTag(DICOM_TAG_SOP_INSTANCE_UID); + finder.SetRetrieveAttachments(true); + break; + + default: + throw OrthancException(ErrorCode_InternalError); } - else - { - /** - * VERSION IN ORTHANC <= 1.12.4 - **/ - DicomIdentifiersVisitor visitor(context_, collection, level); - context_.Apply(visitor, query, level, 0 /* since */, limit); - } + DicomIdentifiersVisitorV2 visitor(collection); + finder.Execute(visitor, context_); return true; } @@ -1707,23 +1484,7 @@ true /* case sensitive */, true /* mandatory tag */); mime = MimeType_Json; - - if (true) - { - /** - * EXPERIMENTAL VERSION - **/ - return GetOrthancJson(content, context_, ResourceType_Study, query); - } - else - { - /** - * VERSION IN ORTHANC <= 1.12.4 - **/ - OrthancJsonVisitor visitor(context_, content, ResourceType_Study); - context_.Apply(visitor, query, ResourceType_Study, 0 /* since */, 0 /* no limit */); - return visitor.IsSuccess(); - } + return GetOrthancJson(content, context_, ResourceType_Study, query); } else if (path.size() == 4 && path[3] == SERIES_INFO) @@ -1735,23 +1496,7 @@ true /* case sensitive */, true /* mandatory tag */); mime = MimeType_Json; - - if (true) - { - /** - * EXPERIMENTAL VERSION - **/ - return GetOrthancJson(content, context_, ResourceType_Series, query); - } - else - { - /** - * VERSION IN ORTHANC <= 1.12.4 - **/ - OrthancJsonVisitor visitor(context_, content, ResourceType_Series); - context_.Apply(visitor, query, ResourceType_Series, 0 /* since */, 0 /* no limit */); - return visitor.IsSuccess(); - } + return GetOrthancJson(content, context_, ResourceType_Series, query); } else if (path.size() == 4 && boost::ends_with(path[3], ".dcm")) @@ -1768,30 +1513,15 @@ mime = MimeType_Dicom; - if (true) - { - /** - * EXPERIMENTAL VERSION - **/ - ResourceFinder finder(ResourceType_Instance, false /* no expand */); - finder.SetDatabaseLookup(query); - finder.SetRetrieveMetadata(true); - finder.SetRetrieveAttachments(true); + ResourceFinder finder(ResourceType_Instance, false /* no expand */); + finder.SetDatabaseLookup(query); + finder.SetRetrieveMetadata(true); + finder.SetRetrieveAttachments(true); - DicomFileVisitorV2 visitor(context_, content, modificationTime); - finder.Execute(visitor, context_); + DicomFileVisitorV2 visitor(context_, content, modificationTime); + finder.Execute(visitor, context_); - return visitor.IsSuccess(); - } - else - { - /** - * VERSION IN ORTHANC <= 1.12.4 - **/ - DicomFileVisitor visitor(context_, content, modificationTime); - context_.Apply(visitor, query, ResourceType_Instance, 0 /* since */, 0 /* no limit */); - return visitor.IsSuccess(); - } + return visitor.IsSuccess(); } else {
--- a/OrthancServer/Sources/OrthancWebDav.h Fri Jul 12 18:41:44 2024 +0200 +++ b/OrthancServer/Sources/OrthancWebDav.h Fri Jul 12 18:55:22 2024 +0200 @@ -38,9 +38,7 @@ typedef std::map<ResourceType, std::string> Templates; class DicomDeleteVisitor; - class DicomFileVisitor; class DicomFileVisitorV2; - class DicomIdentifiersVisitor; class DicomIdentifiersVisitorV2; class InstancesOfSeries; class InternalNode;
--- a/OrthancServer/Sources/ServerContext.cpp Fri Jul 12 18:41:44 2024 +0200 +++ b/OrthancServer/Sources/ServerContext.cpp Fri Jul 12 18:55:22 2024 +0200 @@ -1531,233 +1531,6 @@ } - void ServerContext::Apply(ILookupVisitor& visitor, - const DatabaseLookup& lookup, - ResourceType queryLevel, - const std::set<std::string>& labels, - LabelsConstraint labelsConstraint, - size_t since, - size_t limit) - { - const uint64_t databaseLimit = GetDatabaseLimits(queryLevel); - - std::vector<std::string> resources, instances; - const DicomTagConstraint* dicomModalitiesConstraint = NULL; - - bool hasModalitiesInStudyLookup = (queryLevel == ResourceType_Study && - lookup.GetConstraint(dicomModalitiesConstraint, DICOM_TAG_MODALITIES_IN_STUDY) && - ((dicomModalitiesConstraint->GetConstraintType() == ConstraintType_Equal && !dicomModalitiesConstraint->GetValue().empty()) || - (dicomModalitiesConstraint->GetConstraintType() == ConstraintType_List && !dicomModalitiesConstraint->GetValues().empty()))); - - std::unique_ptr<DatabaseLookup> fastLookup(lookup.Clone()); - - if (hasModalitiesInStudyLookup) - { - fastLookup->RemoveConstraint(DICOM_TAG_MODALITIES_IN_STUDY); - } - - if (true) - { - /** - * EXPERIMENTAL VERSION - **/ - - ResourceFinder finder(queryLevel, false /* TODO-FIND: don't expand for now */); - finder.SetDatabaseLimits(databaseLimit); - finder.SetDatabaseLookup(lookup); - finder.SetLabels(labels); - finder.SetLabelsConstraint(labelsConstraint); - - if (queryLevel != ResourceType_Instance) - { - finder.SetRetrieveOneInstanceIdentifier(true); - } - - FindResponse response; - finder.Execute(response, GetIndex()); - - resources.resize(response.GetSize()); - instances.resize(response.GetSize()); - - for (size_t i = 0; i < response.GetSize(); i++) - { - const FindResponse::Resource& resource = response.GetResourceByIndex(i); - resources[i] = resource.GetIdentifier(); - - if (queryLevel == ResourceType_Instance) - { - instances[i] = resource.GetIdentifier(); - } - else - { - instances[i] = resource.GetOneInstanceIdentifier(); - } - } - } - else - { - /** - * VERSION IN ORTHANC <= 1.12.4 - **/ - - const size_t lookupLimit = (databaseLimit == 0 ? 0 : databaseLimit + 1); - GetIndex().ApplyLookupResources(resources, &instances, *fastLookup, queryLevel, labels, labelsConstraint, lookupLimit); - } - - bool complete = (databaseLimit == 0 || - resources.size() <= databaseLimit); - - LOG(INFO) << "Number of candidate resources after fast DB filtering on main DICOM tags: " << resources.size(); - - /** - * "resources" contains the Orthanc ID of the resource at level - * "queryLevel", "instances" contains one the Orthanc ID of one - * sample instance from this resource. - **/ - assert(resources.size() == instances.size()); - - size_t countResults = 0; - size_t skipped = 0; - - const bool isDicomAsJsonNeeded = visitor.IsDicomAsJsonNeeded(); - - for (size_t i = 0; i < instances.size(); i++) - { - // Optimization in Orthanc 1.5.1 - Don't read the full JSON from - // the disk if only "main DICOM tags" are to be returned - - boost::shared_ptr<Json::Value> dicomAsJson; - - bool hasOnlyMainDicomTags; - DicomMap dicom; - DicomMap allMainDicomTagsFromDB; - - if (!IsStorageAccessAllowedForAnswers(findStorageAccessMode_) - || fastLookup->HasOnlyMainDicomTags()) - { - // Case (1): The main DICOM tags, as stored in the database, - // are sufficient to look for match - - if (!GetIndex().GetAllMainDicomTags(allMainDicomTagsFromDB, instances[i])) - { - // The instance has been removed during the execution of the - // lookup, ignore it - continue; - } - - // New in Orthanc 1.6.0: Only keep the main DICOM tags at the - // level of interest for the query - switch (queryLevel) - { - // WARNING: Don't reorder cases below, and don't add "break" - case ResourceType_Instance: - dicom.MergeMainDicomTags(allMainDicomTagsFromDB, ResourceType_Instance); - - case ResourceType_Series: - dicom.MergeMainDicomTags(allMainDicomTagsFromDB, ResourceType_Series); - - case ResourceType_Study: - dicom.MergeMainDicomTags(allMainDicomTagsFromDB, ResourceType_Study); - - case ResourceType_Patient: - dicom.MergeMainDicomTags(allMainDicomTagsFromDB, ResourceType_Patient); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - hasOnlyMainDicomTags = true; - } - else - { - // Case (2): Need to read the "DICOM-as-JSON" attachment from - // the storage area - dicomAsJson.reset(new Json::Value); - ReadDicomAsJson(*dicomAsJson, instances[i]); - - dicom.FromDicomAsJson(*dicomAsJson); - - // This map contains the entire JSON, i.e. more than the main DICOM tags - hasOnlyMainDicomTags = false; - } - - if (fastLookup->IsMatch(dicom)) - { - bool isMatch = true; - - if (hasModalitiesInStudyLookup) - { - std::set<DicomTag> requestedTags; - requestedTags.insert(DICOM_TAG_MODALITIES_IN_STUDY); - ExpandedResource resource; - ComputeStudyTags(resource, *this, resources[i], requestedTags); - - std::vector<std::string> modalities; - Toolbox::TokenizeString(modalities, resource.GetMainDicomTags().GetValue(DICOM_TAG_MODALITIES_IN_STUDY).GetContent(), '\\'); - bool hasAtLeastOneModalityMatching = false; - for (size_t m = 0; m < modalities.size(); m++) - { - hasAtLeastOneModalityMatching |= dicomModalitiesConstraint->IsMatch(modalities[m]); - } - - isMatch = isMatch && hasAtLeastOneModalityMatching; - // copy the value of ModalitiesInStudy such that it can be reused to build the answer - allMainDicomTagsFromDB.SetValue(DICOM_TAG_MODALITIES_IN_STUDY, resource.GetMainDicomTags().GetValue(DICOM_TAG_MODALITIES_IN_STUDY)); - } - - if (isMatch) - { - if (skipped < since) - { - skipped++; - } - else if (limit != 0 && - countResults >= limit) - { - // Too many results, don't mark as complete - complete = false; - break; - } - else - { - if (IsStorageAccessAllowedForAnswers(findStorageAccessMode_) && - dicomAsJson.get() == NULL && - isDicomAsJsonNeeded) - { - dicomAsJson.reset(new Json::Value); - ReadDicomAsJson(*dicomAsJson, instances[i]); - } - - if (hasOnlyMainDicomTags) - { - // This is Case (1): The variable "dicom" only contains the main DICOM tags - visitor.Visit(resources[i], instances[i], allMainDicomTagsFromDB, dicomAsJson.get()); - } - else - { - // Remove the non-main DICOM tags from "dicom" if Case (2) - // was used, for consistency with Case (1) - - DicomMap mainDicomTags; - mainDicomTags.ExtractMainDicomTags(dicom); - visitor.Visit(resources[i], instances[i], mainDicomTags, dicomAsJson.get()); - } - - countResults ++; - } - } - } - } - - if (complete) - { - visitor.MarkAsComplete(); - } - - LOG(INFO) << "Number of matching resources: " << countResults; - } - bool ServerContext::LookupOrReconstructMetadata(std::string& target, const std::string& publicId, ResourceType level,
--- a/OrthancServer/Sources/ServerContext.h Fri Jul 12 18:41:44 2024 +0200 +++ b/OrthancServer/Sources/ServerContext.h Fri Jul 12 18:55:22 2024 +0200 @@ -66,25 +66,6 @@ friend class ServerIndex; // To access "RemoveFile()" public: - class ILookupVisitor : public boost::noncopyable - { - public: - virtual ~ILookupVisitor() - { - } - - virtual bool IsDicomAsJsonNeeded() const = 0; - - virtual void MarkAsComplete() = 0; - - // NB: "dicomAsJson" must *not* be deleted, and can be NULL if - // "!IsDicomAsJsonNeeded()" - virtual void Visit(const std::string& publicId, - const std::string& instanceId, - const DicomMap& mainDicomTags, - const Json::Value* dicomAsJson) = 0; - }; - struct StoreResult { private: @@ -447,23 +428,6 @@ return (level == ResourceType_Instance ? limitFindInstances_ : limitFindResults_); } - void Apply(ILookupVisitor& visitor, - const DatabaseLookup& lookup, - ResourceType queryLevel, - const std::set<std::string>& labels, - LabelsConstraint labelsConstraint, - size_t since, - size_t limit); - - void Apply(ILookupVisitor& visitor, - const DatabaseLookup& lookup, - ResourceType queryLevel, - size_t since, - size_t limit) - { - Apply(visitor, lookup, queryLevel, std::set<std::string>(), LabelsConstraint_All, since, limit); - } - bool LookupOrReconstructMetadata(std::string& target, const std::string& publicId, ResourceType level,