Mercurial > hg > orthanc
changeset 1357:216db29c5aa9
cont
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 13 May 2015 15:56:41 +0200 |
parents | ab9f3d5910bd |
children | 62d2d35b725e |
files | OrthancServer/ExactResourceFinder.cpp OrthancServer/ExactResourceFinder.h OrthancServer/ServerIndex.cpp |
diffstat | 3 files changed, 216 insertions(+), 185 deletions(-) [+] |
line wrap: on
line diff
--- a/OrthancServer/ExactResourceFinder.cpp Wed May 13 13:19:28 2015 +0200 +++ b/OrthancServer/ExactResourceFinder.cpp Wed May 13 15:56:41 2015 +0200 @@ -34,35 +34,22 @@ #include "ExactResourceFinder.h" #include "FromDcmtkBridge.h" +#include "ServerContext.h" #include <glog/logging.h> #include <boost/algorithm/string/predicate.hpp> namespace Orthanc { - static bool Compare(const std::string& a, - const std::string& b, - bool caseSensitive) - { - if (caseSensitive) - { - return a == b; - } - else - { - return boost::iequals(a, b); - } - } - - class ExactResourceFinder::CandidateResources { private: typedef std::map<DicomTag, std::string> Query; - ServerIndex& index_; - ResourceType level_; - bool isFilterApplied_; + ExactResourceFinder& finder_; + ServerIndex& index_; + ResourceType level_; + bool isFilterApplied_; std::set<std::string> filtered_; @@ -77,7 +64,7 @@ } - void RestrictIdentifier(const DicomTag& tag, + void RestrictIdentifier(const DicomTag& tag, const std::string& value) { assert((level_ == ResourceType_Patient && tag == DICOM_TAG_PATIENT_ID) || @@ -118,21 +105,10 @@ } - void RestrictIdentifier(Query& query, - const DicomTag& tag) - { - Query::iterator it = query.find(tag); - if (it != query.end()) - { - RestrictIdentifier(it->first, it->second); - query.erase(it); - } - } - - public: - CandidateResources(ServerIndex& index) : - index_(index), + CandidateResources(ExactResourceFinder& finder) : + finder_(finder), + index_(finder.context_.GetIndex()), level_(ResourceType_Patient), isFilterApplied_(false) { @@ -157,8 +133,15 @@ it = tmp.begin(); it != tmp.end(); ++it) { std::list<std::string> children; - index_.GetChildren(children, *it); - ListToSet(filtered_, children); + try + { + index_.GetChildren(children, *it); + ListToSet(filtered_, children); + } + catch (OrthancException&) + { + // The resource was removed in the meantime + } } } @@ -200,46 +183,20 @@ } } - - void RestrictIdentifier(Query& query) + + void RestrictIdentifier(const DicomTag& tag) { - switch (level_) + Identifiers::const_iterator it = finder_.identifiers_.find(tag); + if (it != finder_.identifiers_.end()) { - case ResourceType_Patient: - { - RestrictIdentifier(query, DICOM_TAG_PATIENT_ID); - break; - } - - case ResourceType_Study: - { - RestrictIdentifier(query, DICOM_TAG_STUDY_INSTANCE_UID); - RestrictIdentifier(query, DICOM_TAG_ACCESSION_NUMBER); - break; - } - - case ResourceType_Series: - { - RestrictIdentifier(query, DICOM_TAG_SERIES_INSTANCE_UID); - break; - } - - case ResourceType_Instance: - { - RestrictIdentifier(query, DICOM_TAG_SOP_INSTANCE_UID); - break; - } - - default: - throw OrthancException(ErrorCode_InternalError); + RestrictIdentifier(it->first, it->second); } } - void RestrictMainDicomTags(const Query& query, - bool caseSensitive) + void RestrictMainDicomTags() { - if (query.size() == 0) + if (finder_.mainTagsFilter_ == NULL) { return; } @@ -256,91 +213,113 @@ DicomMap mainTags; if (index_.GetMainDicomTags(mainTags, *it, level_)) { - for (Query::const_iterator tag = query.begin(); - tag != query.end(); ++tag) + if (finder_.mainTagsFilter_->Apply(mainTags, level_)) { - assert(DicomMap::IsMainDicomTag(tag->first, level_)); - if (tag->first != DICOM_TAG_PATIENT_ID && - tag->first != DICOM_TAG_STUDY_INSTANCE_UID && - tag->first != DICOM_TAG_ACCESSION_NUMBER && - tag->first != DICOM_TAG_SERIES_INSTANCE_UID && - tag->first != DICOM_TAG_SOP_INSTANCE_UID) - { - LOG(INFO) << "Lookup for main DICOM tag " - << FromDcmtkBridge::GetName(tag->first) << " (value: " << tag->second << ")"; - - const DicomValue* value = mainTags.TestAndGetValue(tag->first); - if (value != NULL && - Compare(value->AsString(), tag->second, caseSensitive)) - { - filtered_.insert(*it); - } - } - } + filtered_.insert(*it); + } } } } }; - ExactResourceFinder::ExactResourceFinder(ServerIndex& index) : - index_(index), + ExactResourceFinder::ExactResourceFinder(ServerContext& context) : + context_(context), level_(ResourceType_Patient), - caseSensitive_(true), - nonMainTagsIgnored_(false) + maxResults_(0) { } - void ExactResourceFinder::AddTag(const std::string& tag, - const std::string& value) - { - AddTag(FromDcmtkBridge::ParseTag(tag.c_str()), value); - } - - - void ExactResourceFinder::ExtractTagsForLevel(Query& target, - Query& source, - ResourceType level) - { - typedef std::set<DicomTag> Tags; - - Tags tags; - DicomMap::GetMainDicomTags(tags, level); - - target.clear(); - - for (Tags::const_iterator tag = tags.begin(); tag != tags.end(); tag++) - { - Query::iterator value = source.find(*tag); - if (value != source.end()) - { - target.insert(*value); - source.erase(value); - } - } - } - - void ExactResourceFinder::ApplyAtLevel(CandidateResources& candidates, - ResourceType level) + ResourceType level) { if (level != ResourceType_Patient) { candidates.GoDown(); } - candidates.RestrictIdentifier(query_); + switch (level_) + { + case ResourceType_Patient: + { + candidates.RestrictIdentifier(DICOM_TAG_PATIENT_ID); + break; + } + + case ResourceType_Study: + { + candidates.RestrictIdentifier(DICOM_TAG_STUDY_INSTANCE_UID); + candidates.RestrictIdentifier(DICOM_TAG_ACCESSION_NUMBER); + break; + } - Query tmp; - ExtractTagsForLevel(tmp, query_, level); - candidates.RestrictMainDicomTags(tmp, caseSensitive_); + case ResourceType_Series: + { + candidates.RestrictIdentifier(DICOM_TAG_SERIES_INSTANCE_UID); + break; + } + + case ResourceType_Instance: + { + candidates.RestrictIdentifier(DICOM_TAG_SOP_INSTANCE_UID); + break; + } + + default: + throw OrthancException(ErrorCode_InternalError); + } + + candidates.RestrictMainDicomTags(); } - void ExactResourceFinder::Apply(std::list<std::string>& result) + + void ExactResourceFinder::SetIdentifier(const DicomTag& tag, + const std::string& value) + { + assert((level_ >= ResourceType_Patient && tag == DICOM_TAG_PATIENT_ID) || + (level_ >= ResourceType_Study && tag == DICOM_TAG_STUDY_INSTANCE_UID) || + (level_ >= ResourceType_Study && tag == DICOM_TAG_ACCESSION_NUMBER) || + (level_ >= ResourceType_Series && tag == DICOM_TAG_SERIES_INSTANCE_UID) || + (level_ >= ResourceType_Instance && tag == DICOM_TAG_SOP_INSTANCE_UID)); + + identifiers_[tag] = value; + } + + + static bool LookupOneInstance(std::string& result, + ServerIndex& index, + const std::string& id, + ResourceType type) { - CandidateResources candidates(index_); + if (type == ResourceType_Instance) + { + result = id; + return true; + } + + std::string childId; + + { + std::list<std::string> children; + index.GetChildInstances(children, id); + + if (children.empty()) + { + return false; + } + + childId = children.front(); + } + + return LookupOneInstance(result, index, childId, GetChildResourceType(type)); + } + + + bool ExactResourceFinder::Apply(std::list<std::string>& result) + { + CandidateResources candidates(*this); ApplyAtLevel(candidates, ResourceType_Patient); @@ -361,14 +340,58 @@ { ApplyAtLevel(candidates, ResourceType_Instance); } - - if (!nonMainTagsIgnored_ && - !query_.empty()) + + if (instanceFilter_ == NULL) + { + candidates.Flatten(result); + + if (maxResults_ != 0 && + result.size() >= maxResults_) + { + result.resize(maxResults_); + return false; + } + else + { + return true; + } + } + else { - LOG(ERROR) << "Invalid query: Searching against a tag that is not valid for the requested level"; - throw OrthancException(ErrorCode_BadRequest); + std::list<std::string> tmp; + candidates.Flatten(tmp); + + result.clear(); + for (std::list<std::string>::const_iterator + resource = tmp.begin(); resource != tmp.end(); ++resource) + { + try + { + std::string instance; + if (LookupOneInstance(instance, context_.GetIndex(), *resource, level_)) + { + Json::Value content; + context_.ReadJson(content, instance); + if (instanceFilter_->Apply(*resource, content)) + { + result.push_back(*resource); + + if (maxResults_ != 0 && + result.size() >= maxResults_) + { + // Too many results, stop before recording this new match + return false; + } + } + } + } + catch (OrthancException&) + { + // This resource has been deleted since the search was started + } + } } - candidates.Flatten(result); + return true; // All the matching resources have been returned } }
--- a/OrthancServer/ExactResourceFinder.h Wed May 13 13:19:28 2015 +0200 +++ b/OrthancServer/ExactResourceFinder.h Wed May 13 15:56:41 2015 +0200 @@ -40,46 +40,48 @@ { class ExactResourceFinder : public boost::noncopyable { + public: + class IMainTagsFilter : public boost::noncopyable + { + public: + virtual ~IMainTagsFilter() + { + } + + bool Apply(const DicomMap& mainTags, + ResourceType level); + }; + + + class IInstanceFilter : public boost::noncopyable + { + public: + virtual ~IInstanceFilter() + { + } + + bool Apply(const std::string& instanceId, + const Json::Value& content); + }; + + private: - typedef std::map<DicomTag, std::string> Query; + typedef std::map<DicomTag, std::string> Identifiers; class CandidateResources; - ServerIndex& index_; - ResourceType level_; - bool caseSensitive_; - bool nonMainTagsIgnored_; - Query query_; - - static void ExtractTagsForLevel(Query& result, - Query& source, - ResourceType level); + ServerContext& context_; + ResourceType level_; + size_t maxResults_; + Identifiers identifiers_; + IMainTagsFilter *mainTagsFilter_; + IInstanceFilter *instanceFilter_; void ApplyAtLevel(CandidateResources& candidates, ResourceType level); public: - ExactResourceFinder(ServerIndex& index); - - bool IsCaseSensitive() const - { - return caseSensitive_; - } - - void SetCaseSensitive(bool sensitive) - { - caseSensitive_ = sensitive; - } - - bool NonMainTagsIgnored() const - { - return nonMainTagsIgnored_; - } - - void SetNonMainTagsIgnored(bool ignored) - { - nonMainTagsIgnored_ = ignored; - } + ExactResourceFinder(ServerContext& context); ResourceType GetLevel() const { @@ -91,16 +93,33 @@ level_ = level; } - void AddTag(const DicomTag& tag, - const std::string& value) + void SetIdentifier(const DicomTag& tag, + const std::string& value); + + void SetMainTagsFilter(IMainTagsFilter& filter) { - query_.insert(std::make_pair(tag, value)); + mainTagsFilter_ = &filter; + } + + void SetInstanceFilter(IInstanceFilter& filter) + { + instanceFilter_ = &filter; } - void AddTag(const std::string& tag, - const std::string& value); + void SetMaxResults(size_t value) + { + maxResults_ = value; + } - void Apply(std::list<std::string>& result); + size_t GetMaxResults() const + { + return maxResults_; + } + + // Returns "true" iff. all the matching resources have been + // returned. Will be "false" if the results were truncated by + // "SetMaxResults()". + bool Apply(std::list<std::string>& result); }; }
--- a/OrthancServer/ServerIndex.cpp Wed May 13 13:19:28 2015 +0200 +++ b/OrthancServer/ServerIndex.cpp Wed May 13 15:56:41 2015 +0200 @@ -1078,19 +1078,8 @@ void ServerIndex::GetAllUuids(std::list<std::string>& target, ResourceType resourceType) { - std::list<std::string> lst; - - { - boost::mutex::scoped_lock lock(mutex_); - db_.GetAllPublicIds(lst, resourceType); - } - - target.clear(); - for (std::list<std::string>::const_iterator - it = lst.begin(); it != lst.end(); ++it) - { - target.push_back(*it); - } + boost::mutex::scoped_lock lock(mutex_); + db_.GetAllPublicIds(target, resourceType); }