comparison OrthancServer/Sources/Database/FindResponse.cpp @ 5586:fc3914c07dd3 find-refactoring

refactoring FindResponse
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 03 May 2024 17:02:02 +0200
parents 74cc31c8db2b
children 1b0fc6685f57
comparison
equal deleted inserted replaced
5583:74cc31c8db2b 5586:fc3914c07dd3
28 #include <cassert> 28 #include <cassert>
29 29
30 30
31 namespace Orthanc 31 namespace Orthanc
32 { 32 {
33 static void ExtractOrthancIdentifiers(OrthancIdentifiers& identifiers, 33 class FindResponse::DicomTagsAtLevel::DicomValue : public boost::noncopyable
34 ResourceType level, 34 {
35 const DicomMap& dicom) 35 public:
36 enum ValueType
37 {
38 ValueType_String,
39 ValueType_Null
40 };
41
42 private:
43 ValueType type_;
44 std::string value_;
45
46 public:
47 DicomValue(ValueType type,
48 const std::string& value) :
49 type_(type),
50 value_(value)
51 {
52 }
53
54 ValueType GetType() const
55 {
56 return type_;
57 }
58
59 const std::string& GetValue() const
60 {
61 switch (type_)
62 {
63 case ValueType_Null:
64 throw OrthancException(ErrorCode_BadSequenceOfCalls);
65
66 case ValueType_String:
67 return value_;
68
69 default:
70 throw OrthancException(ErrorCode_ParameterOutOfRange);
71 }
72 }
73 };
74
75
76 FindResponse::DicomTagsAtLevel::~DicomTagsAtLevel()
77 {
78 for (Content::iterator it = content_.begin(); it != content_.end(); ++it)
79 {
80 assert(it->second != NULL);
81 delete it->second;
82 }
83 }
84
85
86 void FindResponse::DicomTagsAtLevel::AddNullValue(uint16_t group,
87 uint16_t element)
88 {
89 const DicomTag tag(group, element);
90
91 if (content_.find(tag) == content_.end())
92 {
93 content_[tag] = new DicomValue(DicomValue::ValueType_Null, "");
94 }
95 else
96 {
97 throw OrthancException(ErrorCode_BadSequenceOfCalls);
98 }
99 }
100
101
102 void FindResponse::DicomTagsAtLevel::AddStringValue(uint16_t group,
103 uint16_t element,
104 const std::string& value)
105 {
106 const DicomTag tag(group, element);
107
108 if (content_.find(tag) == content_.end())
109 {
110 content_[tag] = new DicomValue(DicomValue::ValueType_String, value);
111 }
112 else
113 {
114 throw OrthancException(ErrorCode_BadSequenceOfCalls);
115 }
116 }
117
118
119 void FindResponse::DicomTagsAtLevel::Fill(DicomMap& target) const
120 {
121 for (Content::const_iterator it = content_.begin(); it != content_.end(); ++it)
122 {
123 assert(it->second != NULL);
124
125 switch (it->second->GetType())
126 {
127 case DicomValue::ValueType_String:
128 target.SetValue(it->first, it->second->GetValue(), false /* not binary */);
129 break;
130
131 case DicomValue::ValueType_Null:
132 target.SetNullValue(it->first);
133 break;
134
135 default:
136 throw OrthancException(ErrorCode_InternalError);
137 }
138 }
139 }
140
141
142 void FindResponse::ChildrenAtLevel::AddIdentifier(const std::string& identifier)
143 {
144 if (identifiers_.find(identifier) == identifiers_.end())
145 {
146 identifiers_.insert(identifier);
147 }
148 else
149 {
150 throw OrthancException(ErrorCode_BadSequenceOfCalls);
151 }
152 }
153
154
155 FindResponse::DicomTagsAtLevel& FindResponse::Item::GetDicomTagsAtLevel(ResourceType level)
36 { 156 {
37 switch (level) 157 switch (level)
38 { 158 {
39 case ResourceType_Patient: 159 case ResourceType_Patient:
40 { 160 return patientTags_;
41 std::string patientId; 161
42 if (!dicom.LookupStringValue(patientId, Orthanc::DICOM_TAG_PATIENT_ID, false)) 162 case ResourceType_Study:
43 { 163 return studyTags_;
44 throw OrthancException(ErrorCode_ParameterOutOfRange); 164
165 case ResourceType_Series:
166 return seriesTags_;
167
168 case ResourceType_Instance:
169 return instanceTags_;
170
171 default:
172 throw OrthancException(ErrorCode_ParameterOutOfRange);
173 }
174 }
175
176
177 FindResponse::ChildrenAtLevel& FindResponse::Item::GetChildrenAtLevel(ResourceType level)
178 {
179 switch (level)
180 {
181 case ResourceType_Study:
182 if (level_ == ResourceType_Patient)
183 {
184 return childrenStudies_;
45 } 185 }
46 else 186 else
47 { 187 {
48 DicomInstanceHasher hasher(patientId, "", "", ""); 188 throw OrthancException(ErrorCode_BadParameterType);
49 identifiers.SetPatientId(hasher.HashPatient()); 189 }
50 } 190
51 break; 191 case ResourceType_Series:
52 } 192 if (level_ == ResourceType_Patient ||
53 193 level_ == ResourceType_Study)
54 case ResourceType_Study: 194 {
55 { 195 return childrenSeries_;
56 std::string patientId, studyInstanceUid;
57 if (!dicom.LookupStringValue(patientId, Orthanc::DICOM_TAG_PATIENT_ID, false) ||
58 !dicom.LookupStringValue(studyInstanceUid, Orthanc::DICOM_TAG_STUDY_INSTANCE_UID, false))
59 {
60 throw OrthancException(ErrorCode_ParameterOutOfRange);
61 } 196 }
62 else 197 else
63 { 198 {
64 DicomInstanceHasher hasher(patientId, studyInstanceUid, "", ""); 199 throw OrthancException(ErrorCode_BadParameterType);
65 identifiers.SetPatientId(hasher.HashPatient()); 200 }
66 identifiers.SetStudyId(hasher.HashStudy()); 201
67 } 202 case ResourceType_Instance:
68 break; 203 if (level_ == ResourceType_Patient ||
69 } 204 level_ == ResourceType_Study ||
70 205 level_ == ResourceType_Series)
71 case ResourceType_Series: 206 {
72 { 207 return childrenInstances_;
73 std::string patientId, studyInstanceUid, seriesInstanceUid;
74 if (!dicom.LookupStringValue(patientId, Orthanc::DICOM_TAG_PATIENT_ID, false) ||
75 !dicom.LookupStringValue(studyInstanceUid, Orthanc::DICOM_TAG_STUDY_INSTANCE_UID, false) ||
76 !dicom.LookupStringValue(seriesInstanceUid, Orthanc::DICOM_TAG_SERIES_INSTANCE_UID, false))
77 {
78 throw OrthancException(ErrorCode_ParameterOutOfRange);
79 } 208 }
80 else 209 else
81 { 210 {
82 DicomInstanceHasher hasher(patientId, studyInstanceUid, seriesInstanceUid, ""); 211 throw OrthancException(ErrorCode_BadParameterType);
83 identifiers.SetPatientId(hasher.HashPatient()); 212 }
84 identifiers.SetStudyId(hasher.HashStudy());
85 identifiers.SetSeriesId(hasher.HashSeries());
86 }
87 break;
88 }
89
90 case ResourceType_Instance:
91 {
92 std::string patientId, studyInstanceUid, seriesInstanceUid, sopInstanceUid;
93 if (!dicom.LookupStringValue(patientId, Orthanc::DICOM_TAG_PATIENT_ID, false) ||
94 !dicom.LookupStringValue(studyInstanceUid, Orthanc::DICOM_TAG_STUDY_INSTANCE_UID, false) ||
95 !dicom.LookupStringValue(seriesInstanceUid, Orthanc::DICOM_TAG_SERIES_INSTANCE_UID, false) ||
96 !dicom.LookupStringValue(sopInstanceUid, Orthanc::DICOM_TAG_SOP_INSTANCE_UID, false))
97 {
98 throw OrthancException(ErrorCode_ParameterOutOfRange);
99 }
100 else
101 {
102 DicomInstanceHasher hasher(patientId, studyInstanceUid, seriesInstanceUid, sopInstanceUid);
103 identifiers.SetPatientId(hasher.HashPatient());
104 identifiers.SetStudyId(hasher.HashStudy());
105 identifiers.SetSeriesId(hasher.HashSeries());
106 identifiers.SetInstanceId(hasher.HashInstance());
107 }
108 break;
109 }
110 213
111 default: 214 default:
112 throw OrthancException(ErrorCode_NotImplemented); 215 throw OrthancException(ErrorCode_ParameterOutOfRange);
113 }
114 }
115
116
117 FindResponse::Item::Item(ResourceType level,
118 DicomMap* dicomMap /* takes ownership */) :
119 dicomMap_(dicomMap)
120 {
121 if (dicomMap == NULL)
122 {
123 throw OrthancException(ErrorCode_NullPointer);
124 }
125 else
126 {
127 ExtractOrthancIdentifiers(identifiers_, level, *dicomMap);
128 } 216 }
129 } 217 }
130 218
131 219
132 void FindResponse::Item::AddMetadata(MetadataType metadata, 220 void FindResponse::Item::AddMetadata(MetadataType metadata,
168 { 256 {
169 target.insert(it->first); 257 target.insert(it->first);
170 } 258 }
171 } 259 }
172 260
173 261 const std::string& FindResponse::Item::GetParentIdentifier() const
174 const DicomMap& FindResponse::Item::GetDicomMap() const 262 {
175 { 263 if (level_ == ResourceType_Patient)
176 if (dicomMap_.get() == NULL) 264 {
177 { 265 throw OrthancException(ErrorCode_BadParameterType);
178 throw OrthancException(ErrorCode_BadSequenceOfCalls); 266 }
179 } 267 else if (HasParentIdentifier())
180 else 268 {
181 { 269 return *parentIdentifier_;
182 return *dicomMap_; 270 }
271 else
272 {
273 throw OrthancException(ErrorCode_BadSequenceOfCalls);
274 }
275 }
276
277
278 void FindResponse::Item::SetParentIdentifier(const std::string& id)
279 {
280 if (level_ == ResourceType_Patient)
281 {
282 throw OrthancException(ErrorCode_BadParameterType);
283 }
284 else if (HasParentIdentifier())
285 {
286 throw OrthancException(ErrorCode_BadSequenceOfCalls);
287 }
288 else
289 {
290 parentIdentifier_.reset(new std::string(id));
291 }
292 }
293
294
295 bool FindResponse::Item::HasParentIdentifier() const
296 {
297 if (level_ == ResourceType_Patient)
298 {
299 throw OrthancException(ErrorCode_BadParameterType);
300 }
301 else
302 {
303 return parentIdentifier_.get() != NULL;
304 }
305 }
306
307
308 void FindResponse::Item::AddLabel(const std::string& label)
309 {
310 if (labels_.find(label) == labels_.end())
311 {
312 labels_.insert(label);
313 }
314 else
315 {
316 throw OrthancException(ErrorCode_BadSequenceOfCalls);
317 }
318 }
319
320
321 void FindResponse::Item::AddAttachment(const FileInfo& attachment)
322 {
323 if (attachments_.find(attachment.GetContentType()) == attachments_.end())
324 {
325 attachments_[attachment.GetContentType()] = attachment;
326 }
327 else
328 {
329 throw OrthancException(ErrorCode_BadSequenceOfCalls);
330 }
331 }
332
333
334 bool FindResponse::Item::LookupAttachment(FileInfo& target, FileContentType type) const
335 {
336 std::map<FileContentType, FileInfo>::const_iterator it = attachments_.find(type);
337 if (it != attachments_.end())
338 {
339 target = it->second;
340 return true;
341 }
342 else
343 {
344 return false;
183 } 345 }
184 } 346 }
185 347
186 348
187 FindResponse::~FindResponse() 349 FindResponse::~FindResponse()
194 } 356 }
195 357
196 358
197 void FindResponse::Add(Item* item /* takes ownership */) 359 void FindResponse::Add(Item* item /* takes ownership */)
198 { 360 {
361 std::unique_ptr<Item> protection(item);
362
199 if (item == NULL) 363 if (item == NULL)
200 { 364 {
201 throw OrthancException(ErrorCode_NullPointer); 365 throw OrthancException(ErrorCode_NullPointer);
202 } 366 }
203 else 367 else
204 { 368 {
205 items_.push_back(item); 369 const std::string& id = item->GetIdentifier();
370
371 if (index_.find(id) == index_.end())
372 {
373 items_.push_back(protection.release());
374 index_[id] = item;
375 }
376 else
377 {
378 throw OrthancException(ErrorCode_BadSequenceOfCalls, "This resource has already been added: " + id);
379 }
206 } 380 }
207 } 381 }
208 382
209 383
210 const FindResponse::Item& FindResponse::GetItem(size_t index) const 384 const FindResponse::Item& FindResponse::GetItem(size_t index) const
218 assert(items_[index] != NULL); 392 assert(items_[index] != NULL);
219 return *items_[index]; 393 return *items_[index];
220 } 394 }
221 } 395 }
222 396
223 void FindResponse::Item::AddDicomTag(uint16_t group, uint16_t element, const std::string& value, bool isBinary) 397
224 { 398 const FindResponse::Item* FindResponse::LookupItem(const std::string& id) const
225 if (dicomMap_.get() == NULL) 399 {
226 { 400 Index::const_iterator found = index_.find(id);
227 dicomMap_.reset(new DicomMap()); 401
228 } 402 if (found == index_.end())
229 403 {
230 dicomMap_->SetValue(group, element, value, isBinary); 404 return NULL;
231 } 405 }
232 406 else
233 void FindResponse::Item::AddChild(const std::string& childId) 407 {
234 { 408 assert(found->second != NULL);
235 children_.push_back(childId); 409 return found->second;
236 } 410 }
237 411 }
238
239 } 412 }