comparison OrthancServer/ResourceFinder.cpp @ 1359:4378a6636187

rename
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 15 May 2015 13:17:37 +0200
parents 62d2d35b725e
children 0649c5aef34a
comparison
equal deleted inserted replaced
1358:62d2d35b725e 1359:4378a6636187
29 * along with this program. If not, see <http://www.gnu.org/licenses/>. 29 * along with this program. If not, see <http://www.gnu.org/licenses/>.
30 **/ 30 **/
31 31
32 32
33 #include "PrecompiledHeadersServer.h" 33 #include "PrecompiledHeadersServer.h"
34 #include "ResourceFinder.h" 34 #include "BaseResourceFinder.h"
35
36 #include "FromDcmtkBridge.h"
37 #include "ServerContext.h"
38
39 #include <glog/logging.h>
40 #include <boost/algorithm/string/predicate.hpp>
35 41
36 namespace Orthanc 42 namespace Orthanc
37 { 43 {
38 namespace 44 class BaseResourceFinder::CandidateResources
39 { 45 {
40 class IConstraint : public boost::noncopyable 46 private:
41 { 47 typedef std::map<DicomTag, std::string> Query;
42 public: 48
43 virtual ~IConstraint() 49 BaseResourceFinder& finder_;
44 { 50 ServerIndex& index_;
45 } 51 ResourceType level_;
46 52 bool isFilterApplied_;
47 virtual bool Apply(const std::string& value) = 0; 53 std::set<std::string> filtered_;
48 }; 54
49 55
56 static void ListToSet(std::set<std::string>& target,
57 const std::list<std::string>& source)
58 {
59 for (std::list<std::string>::const_iterator
60 it = source.begin(); it != source.end(); ++it)
61 {
62 target.insert(*it);
63 }
64 }
65
66
67 void RestrictIdentifier(const DicomTag& tag,
68 const std::string& value)
69 {
70 assert((level_ == ResourceType_Patient && tag == DICOM_TAG_PATIENT_ID) ||
71 (level_ == ResourceType_Study && tag == DICOM_TAG_STUDY_INSTANCE_UID) ||
72 (level_ == ResourceType_Study && tag == DICOM_TAG_ACCESSION_NUMBER) ||
73 (level_ == ResourceType_Series && tag == DICOM_TAG_SERIES_INSTANCE_UID) ||
74 (level_ == ResourceType_Instance && tag == DICOM_TAG_SOP_INSTANCE_UID));
75
76 LOG(INFO) << "Lookup for identifier tag "
77 << FromDcmtkBridge::GetName(tag) << " (value: " << value << ")";
78
79 std::list<std::string> resources;
80 index_.LookupIdentifier(resources, tag, value, level_);
81
82 if (isFilterApplied_)
83 {
84 std::set<std::string> s;
85 ListToSet(s, resources);
86
87 std::set<std::string> tmp = filtered_;
88 filtered_.clear();
89
90 for (std::set<std::string>::const_iterator
91 it = tmp.begin(); it != tmp.end(); ++it)
92 {
93 if (s.find(*it) != s.end())
94 {
95 filtered_.insert(*it);
96 }
97 }
98 }
99 else
100 {
101 assert(filtered_.empty());
102 isFilterApplied_ = true;
103 ListToSet(filtered_, resources);
104 }
105 }
106
107
108 public:
109 CandidateResources(BaseResourceFinder& finder) :
110 finder_(finder),
111 index_(finder.context_.GetIndex()),
112 level_(ResourceType_Patient),
113 isFilterApplied_(false)
114 {
115 }
116
117 ResourceType GetLevel() const
118 {
119 return level_;
120 }
121
122 void GoDown()
123 {
124 assert(level_ != ResourceType_Instance);
125
126 if (isFilterApplied_)
127 {
128 std::set<std::string> tmp = filtered_;
129
130 filtered_.clear();
131
132 for (std::set<std::string>::const_iterator
133 it = tmp.begin(); it != tmp.end(); ++it)
134 {
135 std::list<std::string> children;
136 try
137 {
138 index_.GetChildren(children, *it);
139 ListToSet(filtered_, children);
140 }
141 catch (OrthancException&)
142 {
143 // The resource was removed in the meantime
144 }
145 }
146 }
147
148 switch (level_)
149 {
150 case ResourceType_Patient:
151 level_ = ResourceType_Study;
152 break;
153
154 case ResourceType_Study:
155 level_ = ResourceType_Series;
156 break;
157
158 case ResourceType_Series:
159 level_ = ResourceType_Instance;
160 break;
161
162 default:
163 throw OrthancException(ErrorCode_InternalError);
164 }
165 }
166
167
168 void Flatten(std::list<std::string>& resources) const
169 {
170 resources.clear();
171
172 if (isFilterApplied_)
173 {
174 for (std::set<std::string>::const_iterator
175 it = filtered_.begin(); it != filtered_.end(); ++it)
176 {
177 resources.push_back(*it);
178 }
179 }
180 else
181 {
182 index_.GetAllUuids(resources, level_);
183 }
184 }
50 185
51 186
52 } 187 void RestrictIdentifier(const DicomTag& tag)
53 188 {
189 Identifiers::const_iterator it = finder_.identifiers_.find(tag);
190 if (it != finder_.identifiers_.end())
191 {
192 RestrictIdentifier(it->first, it->second);
193 }
194 }
195
196
197 void RestrictMainDicomTags()
198 {
199 if (finder_.mainTagsFilter_ == NULL)
200 {
201 return;
202 }
203
204 std::list<std::string> resources;
205 Flatten(resources);
206
207 isFilterApplied_ = true;
208 filtered_.clear();
209
210 for (std::list<std::string>::const_iterator
211 it = resources.begin(); it != resources.end(); it++)
212 {
213 DicomMap mainTags;
214 if (index_.GetMainDicomTags(mainTags, *it, level_))
215 {
216 if (finder_.mainTagsFilter_->Apply(mainTags, level_))
217 {
218 filtered_.insert(*it);
219 }
220 }
221 }
222 }
223 };
224
225
226 BaseResourceFinder::BaseResourceFinder(ServerContext& context) :
227 context_(context),
228 level_(ResourceType_Patient),
229 maxResults_(0)
230 {
231 }
232
233
234 void BaseResourceFinder::ApplyAtLevel(CandidateResources& candidates,
235 ResourceType level)
236 {
237 if (level != ResourceType_Patient)
238 {
239 candidates.GoDown();
240 }
241
242 switch (level_)
243 {
244 case ResourceType_Patient:
245 {
246 candidates.RestrictIdentifier(DICOM_TAG_PATIENT_ID);
247 break;
248 }
249
250 case ResourceType_Study:
251 {
252 candidates.RestrictIdentifier(DICOM_TAG_STUDY_INSTANCE_UID);
253 candidates.RestrictIdentifier(DICOM_TAG_ACCESSION_NUMBER);
254 break;
255 }
256
257 case ResourceType_Series:
258 {
259 candidates.RestrictIdentifier(DICOM_TAG_SERIES_INSTANCE_UID);
260 break;
261 }
262
263 case ResourceType_Instance:
264 {
265 candidates.RestrictIdentifier(DICOM_TAG_SOP_INSTANCE_UID);
266 break;
267 }
268
269 default:
270 throw OrthancException(ErrorCode_InternalError);
271 }
272
273 candidates.RestrictMainDicomTags();
274 }
275
276
277
278 void BaseResourceFinder::SetIdentifier(const DicomTag& tag,
279 const std::string& value)
280 {
281 assert((level_ >= ResourceType_Patient && tag == DICOM_TAG_PATIENT_ID) ||
282 (level_ >= ResourceType_Study && tag == DICOM_TAG_STUDY_INSTANCE_UID) ||
283 (level_ >= ResourceType_Study && tag == DICOM_TAG_ACCESSION_NUMBER) ||
284 (level_ >= ResourceType_Series && tag == DICOM_TAG_SERIES_INSTANCE_UID) ||
285 (level_ >= ResourceType_Instance && tag == DICOM_TAG_SOP_INSTANCE_UID));
286
287 identifiers_[tag] = value;
288 }
289
290
291 static bool LookupOneInstance(std::string& result,
292 ServerIndex& index,
293 const std::string& id,
294 ResourceType type)
295 {
296 if (type == ResourceType_Instance)
297 {
298 result = id;
299 return true;
300 }
301
302 std::string childId;
303
304 {
305 std::list<std::string> children;
306 index.GetChildInstances(children, id);
307
308 if (children.empty())
309 {
310 return false;
311 }
312
313 childId = children.front();
314 }
315
316 return LookupOneInstance(result, index, childId, GetChildResourceType(type));
317 }
318
319
320 bool BaseResourceFinder::Apply(std::list<std::string>& result)
321 {
322 CandidateResources candidates(*this);
323
324 ApplyAtLevel(candidates, ResourceType_Patient);
325
326 if (level_ == ResourceType_Study ||
327 level_ == ResourceType_Series ||
328 level_ == ResourceType_Instance)
329 {
330 ApplyAtLevel(candidates, ResourceType_Study);
331 }
332
333 if (level_ == ResourceType_Series ||
334 level_ == ResourceType_Instance)
335 {
336 ApplyAtLevel(candidates, ResourceType_Series);
337 }
338
339 if (level_ == ResourceType_Instance)
340 {
341 ApplyAtLevel(candidates, ResourceType_Instance);
342 }
343
344 if (instanceFilter_ == NULL)
345 {
346 candidates.Flatten(result);
347
348 if (maxResults_ != 0 &&
349 result.size() >= maxResults_)
350 {
351 result.resize(maxResults_);
352 return false;
353 }
354 else
355 {
356 return true;
357 }
358 }
359 else
360 {
361 std::list<std::string> tmp;
362 candidates.Flatten(tmp);
363
364 result.clear();
365 for (std::list<std::string>::const_iterator
366 resource = tmp.begin(); resource != tmp.end(); ++resource)
367 {
368 try
369 {
370 std::string instance;
371 if (LookupOneInstance(instance, context_.GetIndex(), *resource, level_))
372 {
373 Json::Value content;
374 context_.ReadJson(content, instance);
375 if (instanceFilter_->Apply(*resource, content))
376 {
377 result.push_back(*resource);
378
379 if (maxResults_ != 0 &&
380 result.size() >= maxResults_)
381 {
382 // Too many results, stop before recording this new match
383 return false;
384 }
385 }
386 }
387 }
388 catch (OrthancException&)
389 {
390 // This resource has been deleted since the search was started
391 }
392 }
393 }
394
395 return true; // All the matching resources have been returned
396 }
54 } 397 }