comparison OrthancServer/Sources/OrthancFindRequestHandler.cpp @ 5704:0c2f0d72d143 find-refactoring-clean

only keep experimental versions
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 12 Jul 2024 17:17:31 +0200
parents 359a8adb3802
children 58c549b881ae
comparison
equal deleted inserted replaced
5703:12cb6b5c43f0 5704:0c2f0d72d143
80 } 80 }
81 } 81 }
82 } 82 }
83 83
84 84
85 static void AddAnswer(DicomFindAnswers& answers,
86 ServerContext& context,
87 const std::string& publicId,
88 const std::string& instanceId,
89 const DicomMap& mainDicomTags,
90 const Json::Value* dicomAsJson,
91 ResourceType level,
92 const DicomArray& query,
93 const std::list<DicomTag>& sequencesToReturn,
94 const std::string& defaultPrivateCreator,
95 const std::map<uint16_t, std::string>& privateCreators,
96 const std::string& retrieveAet,
97 bool allowStorageAccess)
98 {
99 ExpandedResource resource;
100 std::set<DicomTag> requestedTags;
101
102 query.GetTags(requestedTags);
103 requestedTags.erase(DICOM_TAG_QUERY_RETRIEVE_LEVEL); // this is not part of the answer
104
105 // 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
106 context.ExpandResource(resource, publicId, mainDicomTags, instanceId, dicomAsJson,
107 level, requestedTags, ExpandResourceFlags_IncludeMainDicomTags, allowStorageAccess);
108
109 DicomMap result;
110
111 /**
112 * Add the mandatory "Retrieve AE Title (0008,0054)" tag, which was missing in Orthanc <= 1.7.2.
113 * http://dicom.nema.org/medical/dicom/current/output/html/part04.html#sect_C.4.1.1.3.2
114 * https://groups.google.com/g/orthanc-users/c/-7zNTKR_PMU/m/kfjwzEVNAgAJ
115 **/
116 result.SetValue(DICOM_TAG_RETRIEVE_AE_TITLE, retrieveAet, false /* not binary */);
117
118 for (size_t i = 0; i < query.GetSize(); i++)
119 {
120 if (query.GetElement(i).GetTag() == DICOM_TAG_QUERY_RETRIEVE_LEVEL)
121 {
122 // Fix issue 30 on Google Code (QR response missing "Query/Retrieve Level" (008,0052))
123 result.SetValue(query.GetElement(i).GetTag(), query.GetElement(i).GetValue());
124 }
125 else if (query.GetElement(i).GetTag() == DICOM_TAG_SPECIFIC_CHARACTER_SET)
126 {
127 // Do not include the encoding, this is handled by class ParsedDicomFile
128 }
129 else
130 {
131 const DicomTag& tag = query.GetElement(i).GetTag();
132 const DicomValue* value = resource.GetMainDicomTags().TestAndGetValue(tag);
133
134 if (value != NULL &&
135 !value->IsNull() &&
136 !value->IsBinary())
137 {
138 result.SetValue(tag, value->GetContent(), false);
139 }
140 else
141 {
142 result.SetValue(tag, "", false);
143 }
144 }
145 }
146
147 if (result.GetSize() == 0 &&
148 sequencesToReturn.empty())
149 {
150 CLOG(WARNING, DICOM) << "The C-FIND request does not return any DICOM tag";
151 }
152 else if (sequencesToReturn.empty())
153 {
154 answers.Add(result);
155 }
156 else if (dicomAsJson == NULL)
157 {
158 CLOG(WARNING, DICOM) << "C-FIND query requesting a sequence, but reading JSON from disk is disabled";
159 answers.Add(result);
160 }
161 else
162 {
163 ParsedDicomFile dicom(result, GetDefaultDicomEncoding(),
164 true /* be permissive, cf. issue #136 */, defaultPrivateCreator, privateCreators);
165
166 for (std::list<DicomTag>::const_iterator tag = sequencesToReturn.begin();
167 tag != sequencesToReturn.end(); ++tag)
168 {
169 assert(dicomAsJson != NULL);
170 const Json::Value& source = (*dicomAsJson) [tag->Format()];
171
172 CopySequence(dicom, *tag, source, defaultPrivateCreator, privateCreators);
173 }
174
175 answers.Add(dicom);
176 }
177 }
178
179
180
181 bool OrthancFindRequestHandler::FilterQueryTag(std::string& value /* can be modified */, 85 bool OrthancFindRequestHandler::FilterQueryTag(std::string& value /* can be modified */,
182 ResourceType level, 86 ResourceType level,
183 const DicomTag& tag, 87 const DicomTag& tag,
184 ModalityManufacturer manufacturer) 88 ModalityManufacturer manufacturer)
185 { 89 {
244 context_(context), 148 context_(context),
245 maxResults_(0), 149 maxResults_(0),
246 maxInstances_(0) 150 maxInstances_(0)
247 { 151 {
248 } 152 }
249
250
251 class OrthancFindRequestHandler::LookupVisitor : public ServerContext::ILookupVisitor
252 {
253 private:
254 DicomFindAnswers& answers_;
255 ServerContext& context_;
256 ResourceType level_;
257 const DicomMap& query_;
258 DicomArray queryAsArray_;
259 const std::list<DicomTag>& sequencesToReturn_;
260 std::string defaultPrivateCreator_; // the private creator to use if the group is not defined in the query itself
261 const std::map<uint16_t, std::string>& privateCreators_; // the private creators defined in the query itself
262 std::string retrieveAet_;
263 FindStorageAccessMode findStorageAccessMode_;
264
265 public:
266 LookupVisitor(DicomFindAnswers& answers,
267 ServerContext& context,
268 ResourceType level,
269 const DicomMap& query,
270 const std::list<DicomTag>& sequencesToReturn,
271 const std::map<uint16_t, std::string>& privateCreators,
272 FindStorageAccessMode findStorageAccessMode) :
273 answers_(answers),
274 context_(context),
275 level_(level),
276 query_(query),
277 queryAsArray_(query),
278 sequencesToReturn_(sequencesToReturn),
279 privateCreators_(privateCreators),
280 findStorageAccessMode_(findStorageAccessMode)
281 {
282 answers_.SetComplete(false);
283
284 {
285 OrthancConfiguration::ReaderLock lock;
286 defaultPrivateCreator_ = lock.GetConfiguration().GetDefaultPrivateCreator();
287 retrieveAet_ = lock.GetConfiguration().GetOrthancAET();
288 }
289 }
290
291 virtual bool IsDicomAsJsonNeeded() const ORTHANC_OVERRIDE
292 {
293 // Ask the "DICOM-as-JSON" attachment only if sequences are to
294 // be returned OR if "query_" contains non-main DICOM tags!
295
296 DicomMap withoutSpecialTags;
297 withoutSpecialTags.Assign(query_);
298
299 // Check out "ComputeCounters()"
300 withoutSpecialTags.Remove(DICOM_TAG_MODALITIES_IN_STUDY);
301 withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES);
302 withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES);
303 withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES);
304 withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES);
305 withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES);
306 withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES);
307 withoutSpecialTags.Remove(DICOM_TAG_SOP_CLASSES_IN_STUDY);
308
309 // Check out "AddAnswer()"
310 withoutSpecialTags.Remove(DICOM_TAG_SPECIFIC_CHARACTER_SET);
311 withoutSpecialTags.Remove(DICOM_TAG_QUERY_RETRIEVE_LEVEL);
312
313 return (!sequencesToReturn_.empty() ||
314 !withoutSpecialTags.HasOnlyMainDicomTags());
315 }
316
317 virtual void MarkAsComplete() ORTHANC_OVERRIDE
318 {
319 answers_.SetComplete(true);
320 }
321
322 virtual void Visit(const std::string& publicId,
323 const std::string& instanceId,
324 const DicomMap& mainDicomTags,
325 const Json::Value* dicomAsJson) ORTHANC_OVERRIDE
326 {
327 AddAnswer(answers_, context_, publicId, instanceId, mainDicomTags, dicomAsJson, level_, queryAsArray_, sequencesToReturn_,
328 defaultPrivateCreator_, privateCreators_, retrieveAet_, IsStorageAccessAllowedForAnswers(findStorageAccessMode_));
329 }
330 };
331 153
332 154
333 namespace 155 namespace
334 { 156 {
335 class LookupVisitorV2 : public ResourceFinder::IVisitor 157 class LookupVisitorV2 : public ResourceFinder::IVisitor
620 442
621 /** 443 /**
622 * Run the query. 444 * Run the query.
623 **/ 445 **/
624 446
625 size_t limit = (level == ResourceType_Instance) ? maxInstances_ : maxResults_; 447 ResourceFinder finder(level, false /* don't expand */);
626 448 finder.SetDatabaseLookup(lookup);
627 449 finder.AddRequestedTags(requestedTags);
628 if (true) 450
629 { 451 LookupVisitorV2 visitor(answers, *filteredInput, sequencesToReturn, privateCreators);
630 /** 452 finder.Execute(visitor, context_);
631 * EXPERIMENTAL VERSION
632 **/
633
634 ResourceFinder finder(level, false /* don't expand */);
635 finder.SetDatabaseLookup(lookup);
636 finder.AddRequestedTags(requestedTags);
637
638 LookupVisitorV2 visitor(answers, *filteredInput, sequencesToReturn, privateCreators);
639 finder.Execute(visitor, context_);
640 }
641 else
642 {
643 /**
644 * VERSION IN ORTHANC <= 1.12.4
645 **/
646
647 LookupVisitor visitor(answers, context_, level, *filteredInput, sequencesToReturn, privateCreators, context_.GetFindStorageAccessMode());
648 context_.Apply(visitor, lookup, level, 0 /* "since" is not relevant to C-FIND */, limit);
649 }
650 } 453 }
651 454
652 455
653 void OrthancFindRequestHandler::FormatOrigin(Json::Value& origin, 456 void OrthancFindRequestHandler::FormatOrigin(Json::Value& origin,
654 const std::string& remoteIp, 457 const std::string& remoteIp,