# HG changeset patch # User Sebastien Jodogne # Date 1431525401 -7200 # Node ID 216db29c5aa9dfdd7765e9e115a549f0f01d3c33 # Parent ab9f3d5910bd27ca3744d4a798928be22c35654e cont diff -r ab9f3d5910bd -r 216db29c5aa9 OrthancServer/ExactResourceFinder.cpp --- 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 #include 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 Query; - ServerIndex& index_; - ResourceType level_; - bool isFilterApplied_; + ExactResourceFinder& finder_; + ServerIndex& index_; + ResourceType level_; + bool isFilterApplied_; std::set 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 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 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& 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 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& 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 tmp; + candidates.Flatten(tmp); + + result.clear(); + for (std::list::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 } } diff -r ab9f3d5910bd -r 216db29c5aa9 OrthancServer/ExactResourceFinder.h --- 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 Query; + typedef std::map 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& 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& result); }; } diff -r ab9f3d5910bd -r 216db29c5aa9 OrthancServer/ServerIndex.cpp --- 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& target, ResourceType resourceType) { - std::list lst; - - { - boost::mutex::scoped_lock lock(mutex_); - db_.GetAllPublicIds(lst, resourceType); - } - - target.clear(); - for (std::list::const_iterator - it = lst.begin(); it != lst.end(); ++it) - { - target.push_back(*it); - } + boost::mutex::scoped_lock lock(mutex_); + db_.GetAllPublicIds(target, resourceType); }