Mercurial > hg > orthanc
comparison OrthancServer/Plugins/Engine/OrthancPluginDatabase.cpp @ 4044:d25f4c0fa160 framework
splitting code into OrthancFramework and OrthancServer
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 10 Jun 2020 20:30:34 +0200 |
parents | Plugins/Engine/OrthancPluginDatabase.cpp@94f4a18a79cc |
children | 05b8fd21089c |
comparison
equal
deleted
inserted
replaced
4043:6c6239aec462 | 4044:d25f4c0fa160 |
---|---|
1 /** | |
2 * Orthanc - A Lightweight, RESTful DICOM Store | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium | |
6 * | |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU General Public License as | |
9 * published by the Free Software Foundation, either version 3 of the | |
10 * License, or (at your option) any later version. | |
11 * | |
12 * In addition, as a special exception, the copyright holders of this | |
13 * program give permission to link the code of its release with the | |
14 * OpenSSL project's "OpenSSL" library (or with modified versions of it | |
15 * that use the same license as the "OpenSSL" library), and distribute | |
16 * the linked executables. You must obey the GNU General Public License | |
17 * in all respects for all of the code used other than "OpenSSL". If you | |
18 * modify file(s) with this exception, you may extend this exception to | |
19 * your version of the file(s), but you are not obligated to do so. If | |
20 * you do not wish to do so, delete this exception statement from your | |
21 * version. If you delete this exception statement from all source files | |
22 * in the program, then also delete it here. | |
23 * | |
24 * This program is distributed in the hope that it will be useful, but | |
25 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
27 * General Public License for more details. | |
28 * | |
29 * You should have received a copy of the GNU General Public License | |
30 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
31 **/ | |
32 | |
33 | |
34 #include "../../OrthancServer/PrecompiledHeadersServer.h" | |
35 #include "OrthancPluginDatabase.h" | |
36 | |
37 #if ORTHANC_ENABLE_PLUGINS != 1 | |
38 #error The plugin support is disabled | |
39 #endif | |
40 | |
41 | |
42 #include "../../Core/Logging.h" | |
43 #include "../../Core/OrthancException.h" | |
44 #include "PluginsEnumerations.h" | |
45 | |
46 #include <cassert> | |
47 | |
48 namespace Orthanc | |
49 { | |
50 class OrthancPluginDatabase::Transaction : public IDatabaseWrapper::ITransaction | |
51 { | |
52 private: | |
53 OrthancPluginDatabase& that_; | |
54 | |
55 void CheckSuccess(OrthancPluginErrorCode code) const | |
56 { | |
57 if (code != OrthancPluginErrorCode_Success) | |
58 { | |
59 that_.errorDictionary_.LogError(code, true); | |
60 throw OrthancException(static_cast<ErrorCode>(code)); | |
61 } | |
62 } | |
63 | |
64 public: | |
65 Transaction(OrthancPluginDatabase& that) : | |
66 that_(that) | |
67 { | |
68 } | |
69 | |
70 virtual void Begin() | |
71 { | |
72 CheckSuccess(that_.backend_.startTransaction(that_.payload_)); | |
73 } | |
74 | |
75 virtual void Rollback() | |
76 { | |
77 CheckSuccess(that_.backend_.rollbackTransaction(that_.payload_)); | |
78 } | |
79 | |
80 virtual void Commit(int64_t diskSizeDelta) | |
81 { | |
82 if (that_.fastGetTotalSize_) | |
83 { | |
84 CheckSuccess(that_.backend_.commitTransaction(that_.payload_)); | |
85 } | |
86 else | |
87 { | |
88 if (static_cast<int64_t>(that_.currentDiskSize_) + diskSizeDelta < 0) | |
89 { | |
90 throw OrthancException(ErrorCode_DatabasePlugin); | |
91 } | |
92 | |
93 uint64_t newDiskSize = (that_.currentDiskSize_ + diskSizeDelta); | |
94 | |
95 assert(newDiskSize == that_.GetTotalCompressedSize()); | |
96 | |
97 CheckSuccess(that_.backend_.commitTransaction(that_.payload_)); | |
98 | |
99 // The transaction has succeeded, we can commit the new disk size | |
100 that_.currentDiskSize_ = newDiskSize; | |
101 } | |
102 } | |
103 }; | |
104 | |
105 | |
106 static FileInfo Convert(const OrthancPluginAttachment& attachment) | |
107 { | |
108 return FileInfo(attachment.uuid, | |
109 static_cast<FileContentType>(attachment.contentType), | |
110 attachment.uncompressedSize, | |
111 attachment.uncompressedHash, | |
112 static_cast<CompressionType>(attachment.compressionType), | |
113 attachment.compressedSize, | |
114 attachment.compressedHash); | |
115 } | |
116 | |
117 | |
118 void OrthancPluginDatabase::CheckSuccess(OrthancPluginErrorCode code) | |
119 { | |
120 if (code != OrthancPluginErrorCode_Success) | |
121 { | |
122 errorDictionary_.LogError(code, true); | |
123 throw OrthancException(static_cast<ErrorCode>(code)); | |
124 } | |
125 } | |
126 | |
127 | |
128 void OrthancPluginDatabase::ResetAnswers() | |
129 { | |
130 type_ = _OrthancPluginDatabaseAnswerType_None; | |
131 | |
132 answerDicomMap_ = NULL; | |
133 answerChanges_ = NULL; | |
134 answerExportedResources_ = NULL; | |
135 answerDone_ = NULL; | |
136 answerMatchingResources_ = NULL; | |
137 answerMatchingInstances_ = NULL; | |
138 answerMetadata_ = NULL; | |
139 } | |
140 | |
141 | |
142 void OrthancPluginDatabase::ForwardAnswers(std::list<int64_t>& target) | |
143 { | |
144 if (type_ != _OrthancPluginDatabaseAnswerType_None && | |
145 type_ != _OrthancPluginDatabaseAnswerType_Int64) | |
146 { | |
147 throw OrthancException(ErrorCode_DatabasePlugin); | |
148 } | |
149 | |
150 target.clear(); | |
151 | |
152 if (type_ == _OrthancPluginDatabaseAnswerType_Int64) | |
153 { | |
154 for (std::list<int64_t>::const_iterator | |
155 it = answerInt64_.begin(); it != answerInt64_.end(); ++it) | |
156 { | |
157 target.push_back(*it); | |
158 } | |
159 } | |
160 } | |
161 | |
162 | |
163 void OrthancPluginDatabase::ForwardAnswers(std::list<std::string>& target) | |
164 { | |
165 if (type_ != _OrthancPluginDatabaseAnswerType_None && | |
166 type_ != _OrthancPluginDatabaseAnswerType_String) | |
167 { | |
168 throw OrthancException(ErrorCode_DatabasePlugin); | |
169 } | |
170 | |
171 target.clear(); | |
172 | |
173 if (type_ == _OrthancPluginDatabaseAnswerType_String) | |
174 { | |
175 for (std::list<std::string>::const_iterator | |
176 it = answerStrings_.begin(); it != answerStrings_.end(); ++it) | |
177 { | |
178 target.push_back(*it); | |
179 } | |
180 } | |
181 } | |
182 | |
183 | |
184 bool OrthancPluginDatabase::ForwardSingleAnswer(std::string& target) | |
185 { | |
186 if (type_ == _OrthancPluginDatabaseAnswerType_None) | |
187 { | |
188 return false; | |
189 } | |
190 else if (type_ == _OrthancPluginDatabaseAnswerType_String && | |
191 answerStrings_.size() == 1) | |
192 { | |
193 target = answerStrings_.front(); | |
194 return true; | |
195 } | |
196 else | |
197 { | |
198 throw OrthancException(ErrorCode_DatabasePlugin); | |
199 } | |
200 } | |
201 | |
202 | |
203 bool OrthancPluginDatabase::ForwardSingleAnswer(int64_t& target) | |
204 { | |
205 if (type_ == _OrthancPluginDatabaseAnswerType_None) | |
206 { | |
207 return false; | |
208 } | |
209 else if (type_ == _OrthancPluginDatabaseAnswerType_Int64 && | |
210 answerInt64_.size() == 1) | |
211 { | |
212 target = answerInt64_.front(); | |
213 return true; | |
214 } | |
215 else | |
216 { | |
217 throw OrthancException(ErrorCode_DatabasePlugin); | |
218 } | |
219 } | |
220 | |
221 | |
222 OrthancPluginDatabase::OrthancPluginDatabase(SharedLibrary& library, | |
223 PluginsErrorDictionary& errorDictionary, | |
224 const OrthancPluginDatabaseBackend& backend, | |
225 const OrthancPluginDatabaseExtensions* extensions, | |
226 size_t extensionsSize, | |
227 void *payload) : | |
228 library_(library), | |
229 errorDictionary_(errorDictionary), | |
230 backend_(backend), | |
231 payload_(payload), | |
232 listener_(NULL) | |
233 { | |
234 static const char* const MISSING = " Missing extension in database index plugin: "; | |
235 | |
236 ResetAnswers(); | |
237 | |
238 memset(&extensions_, 0, sizeof(extensions_)); | |
239 | |
240 size_t size = sizeof(extensions_); | |
241 if (extensionsSize < size) | |
242 { | |
243 size = extensionsSize; // Not all the extensions are available | |
244 } | |
245 | |
246 memcpy(&extensions_, extensions, size); | |
247 | |
248 bool isOptimal = true; | |
249 | |
250 if (extensions_.lookupResources == NULL) | |
251 { | |
252 LOG(INFO) << MISSING << "LookupIdentifierRange()"; | |
253 isOptimal = false; | |
254 } | |
255 | |
256 if (extensions_.createInstance == NULL) | |
257 { | |
258 LOG(INFO) << MISSING << "CreateInstance()"; | |
259 isOptimal = false; | |
260 } | |
261 | |
262 if (extensions_.setResourcesContent == NULL) | |
263 { | |
264 LOG(INFO) << MISSING << "SetResourcesContent()"; | |
265 isOptimal = false; | |
266 } | |
267 | |
268 if (extensions_.getChildrenMetadata == NULL) | |
269 { | |
270 LOG(INFO) << MISSING << "GetChildrenMetadata()"; | |
271 isOptimal = false; | |
272 } | |
273 | |
274 if (extensions_.getAllMetadata == NULL) | |
275 { | |
276 LOG(INFO) << MISSING << "GetAllMetadata()"; | |
277 isOptimal = false; | |
278 } | |
279 | |
280 if (extensions_.lookupResourceAndParent == NULL) | |
281 { | |
282 LOG(INFO) << MISSING << "LookupResourceAndParent()"; | |
283 isOptimal = false; | |
284 } | |
285 | |
286 if (isOptimal) | |
287 { | |
288 LOG(INFO) << "The performance of the database index plugin " | |
289 << "is optimal for this version of Orthanc"; | |
290 } | |
291 else | |
292 { | |
293 LOG(WARNING) << "Performance warning in the database index: " | |
294 << "Some extensions are missing in the plugin"; | |
295 } | |
296 | |
297 if (extensions_.getLastChangeIndex == NULL) | |
298 { | |
299 LOG(WARNING) << "The database extension GetLastChangeIndex() is missing"; | |
300 } | |
301 | |
302 if (extensions_.tagMostRecentPatient == NULL) | |
303 { | |
304 LOG(WARNING) << "The database extension TagMostRecentPatient() is missing " | |
305 << "(affected by issue 58)"; | |
306 } | |
307 } | |
308 | |
309 | |
310 void OrthancPluginDatabase::Open() | |
311 { | |
312 CheckSuccess(backend_.open(payload_)); | |
313 | |
314 { | |
315 Transaction transaction(*this); | |
316 transaction.Begin(); | |
317 | |
318 std::string tmp; | |
319 fastGetTotalSize_ = | |
320 (LookupGlobalProperty(tmp, GlobalProperty_GetTotalSizeIsFast) && | |
321 tmp == "1"); | |
322 | |
323 if (fastGetTotalSize_) | |
324 { | |
325 currentDiskSize_ = 0; // Unused | |
326 } | |
327 else | |
328 { | |
329 // This is the case of database plugins using Orthanc SDK <= 1.5.2 | |
330 LOG(WARNING) << "Your database index plugin is not compatible with multiple Orthanc writers"; | |
331 currentDiskSize_ = GetTotalCompressedSize(); | |
332 } | |
333 | |
334 transaction.Commit(0); | |
335 } | |
336 } | |
337 | |
338 | |
339 void OrthancPluginDatabase::AddAttachment(int64_t id, | |
340 const FileInfo& attachment) | |
341 { | |
342 OrthancPluginAttachment tmp; | |
343 tmp.uuid = attachment.GetUuid().c_str(); | |
344 tmp.contentType = static_cast<int32_t>(attachment.GetContentType()); | |
345 tmp.uncompressedSize = attachment.GetUncompressedSize(); | |
346 tmp.uncompressedHash = attachment.GetUncompressedMD5().c_str(); | |
347 tmp.compressionType = static_cast<int32_t>(attachment.GetCompressionType()); | |
348 tmp.compressedSize = attachment.GetCompressedSize(); | |
349 tmp.compressedHash = attachment.GetCompressedMD5().c_str(); | |
350 | |
351 CheckSuccess(backend_.addAttachment(payload_, id, &tmp)); | |
352 } | |
353 | |
354 | |
355 void OrthancPluginDatabase::AttachChild(int64_t parent, | |
356 int64_t child) | |
357 { | |
358 CheckSuccess(backend_.attachChild(payload_, parent, child)); | |
359 } | |
360 | |
361 | |
362 void OrthancPluginDatabase::ClearChanges() | |
363 { | |
364 CheckSuccess(backend_.clearChanges(payload_)); | |
365 } | |
366 | |
367 | |
368 void OrthancPluginDatabase::ClearExportedResources() | |
369 { | |
370 CheckSuccess(backend_.clearExportedResources(payload_)); | |
371 } | |
372 | |
373 | |
374 int64_t OrthancPluginDatabase::CreateResource(const std::string& publicId, | |
375 ResourceType type) | |
376 { | |
377 int64_t id; | |
378 CheckSuccess(backend_.createResource(&id, payload_, publicId.c_str(), Plugins::Convert(type))); | |
379 return id; | |
380 } | |
381 | |
382 | |
383 void OrthancPluginDatabase::DeleteAttachment(int64_t id, | |
384 FileContentType attachment) | |
385 { | |
386 CheckSuccess(backend_.deleteAttachment(payload_, id, static_cast<int32_t>(attachment))); | |
387 } | |
388 | |
389 | |
390 void OrthancPluginDatabase::DeleteMetadata(int64_t id, | |
391 MetadataType type) | |
392 { | |
393 CheckSuccess(backend_.deleteMetadata(payload_, id, static_cast<int32_t>(type))); | |
394 } | |
395 | |
396 | |
397 void OrthancPluginDatabase::DeleteResource(int64_t id) | |
398 { | |
399 CheckSuccess(backend_.deleteResource(payload_, id)); | |
400 } | |
401 | |
402 | |
403 void OrthancPluginDatabase::GetAllMetadata(std::map<MetadataType, std::string>& target, | |
404 int64_t id) | |
405 { | |
406 if (extensions_.getAllMetadata == NULL) | |
407 { | |
408 // Fallback implementation if extension is missing | |
409 target.clear(); | |
410 | |
411 ResetAnswers(); | |
412 CheckSuccess(backend_.listAvailableMetadata(GetContext(), payload_, id)); | |
413 | |
414 if (type_ != _OrthancPluginDatabaseAnswerType_None && | |
415 type_ != _OrthancPluginDatabaseAnswerType_Int32) | |
416 { | |
417 throw OrthancException(ErrorCode_DatabasePlugin); | |
418 } | |
419 | |
420 target.clear(); | |
421 | |
422 if (type_ == _OrthancPluginDatabaseAnswerType_Int32) | |
423 { | |
424 for (std::list<int32_t>::const_iterator | |
425 it = answerInt32_.begin(); it != answerInt32_.end(); ++it) | |
426 { | |
427 MetadataType type = static_cast<MetadataType>(*it); | |
428 | |
429 std::string value; | |
430 if (LookupMetadata(value, id, type)) | |
431 { | |
432 target[type] = value; | |
433 } | |
434 } | |
435 } | |
436 } | |
437 else | |
438 { | |
439 ResetAnswers(); | |
440 | |
441 answerMetadata_ = ⌖ | |
442 target.clear(); | |
443 | |
444 CheckSuccess(extensions_.getAllMetadata(GetContext(), payload_, id)); | |
445 | |
446 if (type_ != _OrthancPluginDatabaseAnswerType_None && | |
447 type_ != _OrthancPluginDatabaseAnswerType_Metadata) | |
448 { | |
449 throw OrthancException(ErrorCode_DatabasePlugin); | |
450 } | |
451 } | |
452 } | |
453 | |
454 | |
455 void OrthancPluginDatabase::GetAllInternalIds(std::list<int64_t>& target, | |
456 ResourceType resourceType) | |
457 { | |
458 if (extensions_.getAllInternalIds == NULL) | |
459 { | |
460 throw OrthancException(ErrorCode_DatabasePlugin, | |
461 "The database plugin does not implement the mandatory GetAllInternalIds() extension"); | |
462 } | |
463 | |
464 ResetAnswers(); | |
465 CheckSuccess(extensions_.getAllInternalIds(GetContext(), payload_, Plugins::Convert(resourceType))); | |
466 ForwardAnswers(target); | |
467 } | |
468 | |
469 | |
470 void OrthancPluginDatabase::GetAllPublicIds(std::list<std::string>& target, | |
471 ResourceType resourceType) | |
472 { | |
473 ResetAnswers(); | |
474 CheckSuccess(backend_.getAllPublicIds(GetContext(), payload_, Plugins::Convert(resourceType))); | |
475 ForwardAnswers(target); | |
476 } | |
477 | |
478 | |
479 void OrthancPluginDatabase::GetAllPublicIds(std::list<std::string>& target, | |
480 ResourceType resourceType, | |
481 size_t since, | |
482 size_t limit) | |
483 { | |
484 if (extensions_.getAllPublicIdsWithLimit != NULL) | |
485 { | |
486 // This extension is available since Orthanc 0.9.4 | |
487 ResetAnswers(); | |
488 CheckSuccess(extensions_.getAllPublicIdsWithLimit | |
489 (GetContext(), payload_, Plugins::Convert(resourceType), since, limit)); | |
490 ForwardAnswers(target); | |
491 } | |
492 else | |
493 { | |
494 // The extension is not available in the database plugin, use a | |
495 // fallback implementation | |
496 target.clear(); | |
497 | |
498 if (limit == 0) | |
499 { | |
500 return; | |
501 } | |
502 | |
503 std::list<std::string> tmp; | |
504 GetAllPublicIds(tmp, resourceType); | |
505 | |
506 if (tmp.size() <= since) | |
507 { | |
508 // Not enough results => empty answer | |
509 return; | |
510 } | |
511 | |
512 std::list<std::string>::iterator current = tmp.begin(); | |
513 std::advance(current, since); | |
514 | |
515 while (limit > 0 && current != tmp.end()) | |
516 { | |
517 target.push_back(*current); | |
518 --limit; | |
519 ++current; | |
520 } | |
521 } | |
522 } | |
523 | |
524 | |
525 | |
526 void OrthancPluginDatabase::GetChanges(std::list<ServerIndexChange>& target /*out*/, | |
527 bool& done /*out*/, | |
528 int64_t since, | |
529 uint32_t maxResults) | |
530 { | |
531 ResetAnswers(); | |
532 answerChanges_ = ⌖ | |
533 answerDone_ = &done; | |
534 done = false; | |
535 | |
536 CheckSuccess(backend_.getChanges(GetContext(), payload_, since, maxResults)); | |
537 } | |
538 | |
539 | |
540 void OrthancPluginDatabase::GetChildrenInternalId(std::list<int64_t>& target, | |
541 int64_t id) | |
542 { | |
543 ResetAnswers(); | |
544 CheckSuccess(backend_.getChildrenInternalId(GetContext(), payload_, id)); | |
545 ForwardAnswers(target); | |
546 } | |
547 | |
548 | |
549 void OrthancPluginDatabase::GetChildrenPublicId(std::list<std::string>& target, | |
550 int64_t id) | |
551 { | |
552 ResetAnswers(); | |
553 CheckSuccess(backend_.getChildrenPublicId(GetContext(), payload_, id)); | |
554 ForwardAnswers(target); | |
555 } | |
556 | |
557 | |
558 void OrthancPluginDatabase::GetExportedResources(std::list<ExportedResource>& target /*out*/, | |
559 bool& done /*out*/, | |
560 int64_t since, | |
561 uint32_t maxResults) | |
562 { | |
563 ResetAnswers(); | |
564 answerExportedResources_ = ⌖ | |
565 answerDone_ = &done; | |
566 done = false; | |
567 | |
568 CheckSuccess(backend_.getExportedResources(GetContext(), payload_, since, maxResults)); | |
569 } | |
570 | |
571 | |
572 void OrthancPluginDatabase::GetLastChange(std::list<ServerIndexChange>& target /*out*/) | |
573 { | |
574 bool ignored = false; | |
575 | |
576 ResetAnswers(); | |
577 answerChanges_ = ⌖ | |
578 answerDone_ = &ignored; | |
579 | |
580 CheckSuccess(backend_.getLastChange(GetContext(), payload_)); | |
581 } | |
582 | |
583 | |
584 void OrthancPluginDatabase::GetLastExportedResource(std::list<ExportedResource>& target /*out*/) | |
585 { | |
586 bool ignored = false; | |
587 | |
588 ResetAnswers(); | |
589 answerExportedResources_ = ⌖ | |
590 answerDone_ = &ignored; | |
591 | |
592 CheckSuccess(backend_.getLastExportedResource(GetContext(), payload_)); | |
593 } | |
594 | |
595 | |
596 void OrthancPluginDatabase::GetMainDicomTags(DicomMap& map, | |
597 int64_t id) | |
598 { | |
599 ResetAnswers(); | |
600 answerDicomMap_ = ↦ | |
601 | |
602 CheckSuccess(backend_.getMainDicomTags(GetContext(), payload_, id)); | |
603 } | |
604 | |
605 | |
606 std::string OrthancPluginDatabase::GetPublicId(int64_t resourceId) | |
607 { | |
608 ResetAnswers(); | |
609 std::string s; | |
610 | |
611 CheckSuccess(backend_.getPublicId(GetContext(), payload_, resourceId)); | |
612 | |
613 if (!ForwardSingleAnswer(s)) | |
614 { | |
615 throw OrthancException(ErrorCode_DatabasePlugin); | |
616 } | |
617 | |
618 return s; | |
619 } | |
620 | |
621 | |
622 uint64_t OrthancPluginDatabase::GetResourceCount(ResourceType resourceType) | |
623 { | |
624 uint64_t count; | |
625 CheckSuccess(backend_.getResourceCount(&count, payload_, Plugins::Convert(resourceType))); | |
626 return count; | |
627 } | |
628 | |
629 | |
630 ResourceType OrthancPluginDatabase::GetResourceType(int64_t resourceId) | |
631 { | |
632 OrthancPluginResourceType type; | |
633 CheckSuccess(backend_.getResourceType(&type, payload_, resourceId)); | |
634 return Plugins::Convert(type); | |
635 } | |
636 | |
637 | |
638 uint64_t OrthancPluginDatabase::GetTotalCompressedSize() | |
639 { | |
640 uint64_t size; | |
641 CheckSuccess(backend_.getTotalCompressedSize(&size, payload_)); | |
642 return size; | |
643 } | |
644 | |
645 | |
646 uint64_t OrthancPluginDatabase::GetTotalUncompressedSize() | |
647 { | |
648 uint64_t size; | |
649 CheckSuccess(backend_.getTotalUncompressedSize(&size, payload_)); | |
650 return size; | |
651 } | |
652 | |
653 | |
654 bool OrthancPluginDatabase::IsExistingResource(int64_t internalId) | |
655 { | |
656 int32_t existing; | |
657 CheckSuccess(backend_.isExistingResource(&existing, payload_, internalId)); | |
658 return (existing != 0); | |
659 } | |
660 | |
661 | |
662 bool OrthancPluginDatabase::IsProtectedPatient(int64_t internalId) | |
663 { | |
664 int32_t isProtected; | |
665 CheckSuccess(backend_.isProtectedPatient(&isProtected, payload_, internalId)); | |
666 return (isProtected != 0); | |
667 } | |
668 | |
669 | |
670 void OrthancPluginDatabase::ListAvailableAttachments(std::list<FileContentType>& target, | |
671 int64_t id) | |
672 { | |
673 ResetAnswers(); | |
674 | |
675 CheckSuccess(backend_.listAvailableAttachments(GetContext(), payload_, id)); | |
676 | |
677 if (type_ != _OrthancPluginDatabaseAnswerType_None && | |
678 type_ != _OrthancPluginDatabaseAnswerType_Int32) | |
679 { | |
680 throw OrthancException(ErrorCode_DatabasePlugin); | |
681 } | |
682 | |
683 target.clear(); | |
684 | |
685 if (type_ == _OrthancPluginDatabaseAnswerType_Int32) | |
686 { | |
687 for (std::list<int32_t>::const_iterator | |
688 it = answerInt32_.begin(); it != answerInt32_.end(); ++it) | |
689 { | |
690 target.push_back(static_cast<FileContentType>(*it)); | |
691 } | |
692 } | |
693 } | |
694 | |
695 | |
696 void OrthancPluginDatabase::LogChange(int64_t internalId, | |
697 const ServerIndexChange& change) | |
698 { | |
699 OrthancPluginChange tmp; | |
700 tmp.seq = change.GetSeq(); | |
701 tmp.changeType = static_cast<int32_t>(change.GetChangeType()); | |
702 tmp.resourceType = Plugins::Convert(change.GetResourceType()); | |
703 tmp.publicId = change.GetPublicId().c_str(); | |
704 tmp.date = change.GetDate().c_str(); | |
705 | |
706 CheckSuccess(backend_.logChange(payload_, &tmp)); | |
707 } | |
708 | |
709 | |
710 void OrthancPluginDatabase::LogExportedResource(const ExportedResource& resource) | |
711 { | |
712 OrthancPluginExportedResource tmp; | |
713 tmp.seq = resource.GetSeq(); | |
714 tmp.resourceType = Plugins::Convert(resource.GetResourceType()); | |
715 tmp.publicId = resource.GetPublicId().c_str(); | |
716 tmp.modality = resource.GetModality().c_str(); | |
717 tmp.date = resource.GetDate().c_str(); | |
718 tmp.patientId = resource.GetPatientId().c_str(); | |
719 tmp.studyInstanceUid = resource.GetStudyInstanceUid().c_str(); | |
720 tmp.seriesInstanceUid = resource.GetSeriesInstanceUid().c_str(); | |
721 tmp.sopInstanceUid = resource.GetSopInstanceUid().c_str(); | |
722 | |
723 CheckSuccess(backend_.logExportedResource(payload_, &tmp)); | |
724 } | |
725 | |
726 | |
727 bool OrthancPluginDatabase::LookupAttachment(FileInfo& attachment, | |
728 int64_t id, | |
729 FileContentType contentType) | |
730 { | |
731 ResetAnswers(); | |
732 | |
733 CheckSuccess(backend_.lookupAttachment | |
734 (GetContext(), payload_, id, static_cast<int32_t>(contentType))); | |
735 | |
736 if (type_ == _OrthancPluginDatabaseAnswerType_None) | |
737 { | |
738 return false; | |
739 } | |
740 else if (type_ == _OrthancPluginDatabaseAnswerType_Attachment && | |
741 answerAttachments_.size() == 1) | |
742 { | |
743 attachment = answerAttachments_.front(); | |
744 return true; | |
745 } | |
746 else | |
747 { | |
748 throw OrthancException(ErrorCode_DatabasePlugin); | |
749 } | |
750 } | |
751 | |
752 | |
753 bool OrthancPluginDatabase::LookupGlobalProperty(std::string& target, | |
754 GlobalProperty property) | |
755 { | |
756 ResetAnswers(); | |
757 | |
758 CheckSuccess(backend_.lookupGlobalProperty | |
759 (GetContext(), payload_, static_cast<int32_t>(property))); | |
760 | |
761 return ForwardSingleAnswer(target); | |
762 } | |
763 | |
764 | |
765 bool OrthancPluginDatabase::LookupMetadata(std::string& target, | |
766 int64_t id, | |
767 MetadataType type) | |
768 { | |
769 ResetAnswers(); | |
770 CheckSuccess(backend_.lookupMetadata(GetContext(), payload_, id, static_cast<int32_t>(type))); | |
771 return ForwardSingleAnswer(target); | |
772 } | |
773 | |
774 | |
775 bool OrthancPluginDatabase::LookupParent(int64_t& parentId, | |
776 int64_t resourceId) | |
777 { | |
778 ResetAnswers(); | |
779 CheckSuccess(backend_.lookupParent(GetContext(), payload_, resourceId)); | |
780 return ForwardSingleAnswer(parentId); | |
781 } | |
782 | |
783 | |
784 bool OrthancPluginDatabase::LookupResource(int64_t& id, | |
785 ResourceType& type, | |
786 const std::string& publicId) | |
787 { | |
788 ResetAnswers(); | |
789 | |
790 CheckSuccess(backend_.lookupResource(GetContext(), payload_, publicId.c_str())); | |
791 | |
792 if (type_ == _OrthancPluginDatabaseAnswerType_None) | |
793 { | |
794 return false; | |
795 } | |
796 else if (type_ == _OrthancPluginDatabaseAnswerType_Resource && | |
797 answerResources_.size() == 1) | |
798 { | |
799 id = answerResources_.front().first; | |
800 type = answerResources_.front().second; | |
801 return true; | |
802 } | |
803 else | |
804 { | |
805 throw OrthancException(ErrorCode_DatabasePlugin); | |
806 } | |
807 } | |
808 | |
809 | |
810 bool OrthancPluginDatabase::SelectPatientToRecycle(int64_t& internalId) | |
811 { | |
812 ResetAnswers(); | |
813 CheckSuccess(backend_.selectPatientToRecycle(GetContext(), payload_)); | |
814 return ForwardSingleAnswer(internalId); | |
815 } | |
816 | |
817 | |
818 bool OrthancPluginDatabase::SelectPatientToRecycle(int64_t& internalId, | |
819 int64_t patientIdToAvoid) | |
820 { | |
821 ResetAnswers(); | |
822 CheckSuccess(backend_.selectPatientToRecycle2(GetContext(), payload_, patientIdToAvoid)); | |
823 return ForwardSingleAnswer(internalId); | |
824 } | |
825 | |
826 | |
827 void OrthancPluginDatabase::SetGlobalProperty(GlobalProperty property, | |
828 const std::string& value) | |
829 { | |
830 CheckSuccess(backend_.setGlobalProperty | |
831 (payload_, static_cast<int32_t>(property), value.c_str())); | |
832 } | |
833 | |
834 | |
835 void OrthancPluginDatabase::ClearMainDicomTags(int64_t id) | |
836 { | |
837 if (extensions_.clearMainDicomTags == NULL) | |
838 { | |
839 throw OrthancException(ErrorCode_DatabasePlugin, | |
840 "Your custom index plugin does not implement the mandatory ClearMainDicomTags() extension"); | |
841 } | |
842 | |
843 CheckSuccess(extensions_.clearMainDicomTags(payload_, id)); | |
844 } | |
845 | |
846 | |
847 void OrthancPluginDatabase::SetMainDicomTag(int64_t id, | |
848 const DicomTag& tag, | |
849 const std::string& value) | |
850 { | |
851 OrthancPluginDicomTag tmp; | |
852 tmp.group = tag.GetGroup(); | |
853 tmp.element = tag.GetElement(); | |
854 tmp.value = value.c_str(); | |
855 | |
856 CheckSuccess(backend_.setMainDicomTag(payload_, id, &tmp)); | |
857 } | |
858 | |
859 | |
860 void OrthancPluginDatabase::SetIdentifierTag(int64_t id, | |
861 const DicomTag& tag, | |
862 const std::string& value) | |
863 { | |
864 OrthancPluginDicomTag tmp; | |
865 tmp.group = tag.GetGroup(); | |
866 tmp.element = tag.GetElement(); | |
867 tmp.value = value.c_str(); | |
868 | |
869 CheckSuccess(backend_.setIdentifierTag(payload_, id, &tmp)); | |
870 } | |
871 | |
872 | |
873 void OrthancPluginDatabase::SetMetadata(int64_t id, | |
874 MetadataType type, | |
875 const std::string& value) | |
876 { | |
877 CheckSuccess(backend_.setMetadata | |
878 (payload_, id, static_cast<int32_t>(type), value.c_str())); | |
879 } | |
880 | |
881 | |
882 void OrthancPluginDatabase::SetProtectedPatient(int64_t internalId, | |
883 bool isProtected) | |
884 { | |
885 CheckSuccess(backend_.setProtectedPatient(payload_, internalId, isProtected)); | |
886 } | |
887 | |
888 | |
889 IDatabaseWrapper::ITransaction* OrthancPluginDatabase::StartTransaction() | |
890 { | |
891 return new Transaction(*this); | |
892 } | |
893 | |
894 | |
895 static void ProcessEvent(IDatabaseListener& listener, | |
896 const _OrthancPluginDatabaseAnswer& answer) | |
897 { | |
898 switch (answer.type) | |
899 { | |
900 case _OrthancPluginDatabaseAnswerType_DeletedAttachment: | |
901 { | |
902 const OrthancPluginAttachment& attachment = | |
903 *reinterpret_cast<const OrthancPluginAttachment*>(answer.valueGeneric); | |
904 listener.SignalFileDeleted(Convert(attachment)); | |
905 break; | |
906 } | |
907 | |
908 case _OrthancPluginDatabaseAnswerType_RemainingAncestor: | |
909 { | |
910 ResourceType type = Plugins::Convert(static_cast<OrthancPluginResourceType>(answer.valueInt32)); | |
911 listener.SignalRemainingAncestor(type, answer.valueString); | |
912 break; | |
913 } | |
914 | |
915 case _OrthancPluginDatabaseAnswerType_DeletedResource: | |
916 { | |
917 ResourceType type = Plugins::Convert(static_cast<OrthancPluginResourceType>(answer.valueInt32)); | |
918 ServerIndexChange change(ChangeType_Deleted, type, answer.valueString); | |
919 listener.SignalChange(change); | |
920 break; | |
921 } | |
922 | |
923 default: | |
924 throw OrthancException(ErrorCode_DatabasePlugin); | |
925 } | |
926 } | |
927 | |
928 | |
929 unsigned int OrthancPluginDatabase::GetDatabaseVersion() | |
930 { | |
931 if (extensions_.getDatabaseVersion != NULL) | |
932 { | |
933 uint32_t version; | |
934 CheckSuccess(extensions_.getDatabaseVersion(&version, payload_)); | |
935 return version; | |
936 } | |
937 else | |
938 { | |
939 // Before adding the "GetDatabaseVersion()" extension in plugins | |
940 // (OrthancPostgreSQL <= 1.2), the only supported DB schema was | |
941 // version 5. | |
942 return 5; | |
943 } | |
944 } | |
945 | |
946 | |
947 void OrthancPluginDatabase::Upgrade(unsigned int targetVersion, | |
948 IStorageArea& storageArea) | |
949 { | |
950 if (extensions_.upgradeDatabase != NULL) | |
951 { | |
952 Transaction transaction(*this); | |
953 transaction.Begin(); | |
954 | |
955 OrthancPluginErrorCode code = extensions_.upgradeDatabase( | |
956 payload_, targetVersion, | |
957 reinterpret_cast<OrthancPluginStorageArea*>(&storageArea)); | |
958 | |
959 if (code == OrthancPluginErrorCode_Success) | |
960 { | |
961 transaction.Commit(0); | |
962 } | |
963 else | |
964 { | |
965 transaction.Rollback(); | |
966 errorDictionary_.LogError(code, true); | |
967 throw OrthancException(static_cast<ErrorCode>(code)); | |
968 } | |
969 } | |
970 } | |
971 | |
972 | |
973 void OrthancPluginDatabase::AnswerReceived(const _OrthancPluginDatabaseAnswer& answer) | |
974 { | |
975 if (answer.type == _OrthancPluginDatabaseAnswerType_None) | |
976 { | |
977 throw OrthancException(ErrorCode_DatabasePlugin); | |
978 } | |
979 | |
980 if (answer.type == _OrthancPluginDatabaseAnswerType_DeletedAttachment || | |
981 answer.type == _OrthancPluginDatabaseAnswerType_DeletedResource || | |
982 answer.type == _OrthancPluginDatabaseAnswerType_RemainingAncestor) | |
983 { | |
984 assert(listener_ != NULL); | |
985 ProcessEvent(*listener_, answer); | |
986 return; | |
987 } | |
988 | |
989 if (type_ == _OrthancPluginDatabaseAnswerType_None) | |
990 { | |
991 type_ = answer.type; | |
992 | |
993 switch (type_) | |
994 { | |
995 case _OrthancPluginDatabaseAnswerType_Int32: | |
996 answerInt32_.clear(); | |
997 break; | |
998 | |
999 case _OrthancPluginDatabaseAnswerType_Int64: | |
1000 answerInt64_.clear(); | |
1001 break; | |
1002 | |
1003 case _OrthancPluginDatabaseAnswerType_Resource: | |
1004 answerResources_.clear(); | |
1005 break; | |
1006 | |
1007 case _OrthancPluginDatabaseAnswerType_Attachment: | |
1008 answerAttachments_.clear(); | |
1009 break; | |
1010 | |
1011 case _OrthancPluginDatabaseAnswerType_String: | |
1012 answerStrings_.clear(); | |
1013 break; | |
1014 | |
1015 case _OrthancPluginDatabaseAnswerType_DicomTag: | |
1016 assert(answerDicomMap_ != NULL); | |
1017 answerDicomMap_->Clear(); | |
1018 break; | |
1019 | |
1020 case _OrthancPluginDatabaseAnswerType_Change: | |
1021 assert(answerChanges_ != NULL); | |
1022 answerChanges_->clear(); | |
1023 break; | |
1024 | |
1025 case _OrthancPluginDatabaseAnswerType_ExportedResource: | |
1026 assert(answerExportedResources_ != NULL); | |
1027 answerExportedResources_->clear(); | |
1028 break; | |
1029 | |
1030 case _OrthancPluginDatabaseAnswerType_MatchingResource: | |
1031 assert(answerMatchingResources_ != NULL); | |
1032 answerMatchingResources_->clear(); | |
1033 | |
1034 if (answerMatchingInstances_ != NULL) | |
1035 { | |
1036 answerMatchingInstances_->clear(); | |
1037 } | |
1038 | |
1039 break; | |
1040 | |
1041 case _OrthancPluginDatabaseAnswerType_Metadata: | |
1042 assert(answerMetadata_ != NULL); | |
1043 answerMetadata_->clear(); | |
1044 break; | |
1045 | |
1046 default: | |
1047 throw OrthancException(ErrorCode_DatabasePlugin, | |
1048 "Unhandled type of answer for custom index plugin: " + | |
1049 boost::lexical_cast<std::string>(answer.type)); | |
1050 } | |
1051 } | |
1052 else if (type_ != answer.type) | |
1053 { | |
1054 throw OrthancException(ErrorCode_DatabasePlugin, | |
1055 "Error in the plugin protocol: Cannot change the answer type"); | |
1056 } | |
1057 | |
1058 switch (answer.type) | |
1059 { | |
1060 case _OrthancPluginDatabaseAnswerType_Int32: | |
1061 { | |
1062 answerInt32_.push_back(answer.valueInt32); | |
1063 break; | |
1064 } | |
1065 | |
1066 case _OrthancPluginDatabaseAnswerType_Int64: | |
1067 { | |
1068 answerInt64_.push_back(answer.valueInt64); | |
1069 break; | |
1070 } | |
1071 | |
1072 case _OrthancPluginDatabaseAnswerType_Resource: | |
1073 { | |
1074 OrthancPluginResourceType type = static_cast<OrthancPluginResourceType>(answer.valueInt32); | |
1075 answerResources_.push_back(std::make_pair(answer.valueInt64, Plugins::Convert(type))); | |
1076 break; | |
1077 } | |
1078 | |
1079 case _OrthancPluginDatabaseAnswerType_Attachment: | |
1080 { | |
1081 const OrthancPluginAttachment& attachment = | |
1082 *reinterpret_cast<const OrthancPluginAttachment*>(answer.valueGeneric); | |
1083 | |
1084 answerAttachments_.push_back(Convert(attachment)); | |
1085 break; | |
1086 } | |
1087 | |
1088 case _OrthancPluginDatabaseAnswerType_DicomTag: | |
1089 { | |
1090 const OrthancPluginDicomTag& tag = *reinterpret_cast<const OrthancPluginDicomTag*>(answer.valueGeneric); | |
1091 assert(answerDicomMap_ != NULL); | |
1092 answerDicomMap_->SetValue(tag.group, tag.element, std::string(tag.value), false); | |
1093 break; | |
1094 } | |
1095 | |
1096 case _OrthancPluginDatabaseAnswerType_String: | |
1097 { | |
1098 if (answer.valueString == NULL) | |
1099 { | |
1100 throw OrthancException(ErrorCode_DatabasePlugin); | |
1101 } | |
1102 | |
1103 if (type_ == _OrthancPluginDatabaseAnswerType_None) | |
1104 { | |
1105 type_ = _OrthancPluginDatabaseAnswerType_String; | |
1106 answerStrings_.clear(); | |
1107 } | |
1108 else if (type_ != _OrthancPluginDatabaseAnswerType_String) | |
1109 { | |
1110 throw OrthancException(ErrorCode_DatabasePlugin); | |
1111 } | |
1112 | |
1113 answerStrings_.push_back(std::string(answer.valueString)); | |
1114 break; | |
1115 } | |
1116 | |
1117 case _OrthancPluginDatabaseAnswerType_Change: | |
1118 { | |
1119 assert(answerDone_ != NULL); | |
1120 if (answer.valueUint32 == 1) | |
1121 { | |
1122 *answerDone_ = true; | |
1123 } | |
1124 else if (*answerDone_) | |
1125 { | |
1126 throw OrthancException(ErrorCode_DatabasePlugin); | |
1127 } | |
1128 else | |
1129 { | |
1130 const OrthancPluginChange& change = | |
1131 *reinterpret_cast<const OrthancPluginChange*>(answer.valueGeneric); | |
1132 assert(answerChanges_ != NULL); | |
1133 answerChanges_->push_back | |
1134 (ServerIndexChange(change.seq, | |
1135 static_cast<ChangeType>(change.changeType), | |
1136 Plugins::Convert(change.resourceType), | |
1137 change.publicId, | |
1138 change.date)); | |
1139 } | |
1140 | |
1141 break; | |
1142 } | |
1143 | |
1144 case _OrthancPluginDatabaseAnswerType_ExportedResource: | |
1145 { | |
1146 assert(answerDone_ != NULL); | |
1147 if (answer.valueUint32 == 1) | |
1148 { | |
1149 *answerDone_ = true; | |
1150 } | |
1151 else if (*answerDone_) | |
1152 { | |
1153 throw OrthancException(ErrorCode_DatabasePlugin); | |
1154 } | |
1155 else | |
1156 { | |
1157 const OrthancPluginExportedResource& exported = | |
1158 *reinterpret_cast<const OrthancPluginExportedResource*>(answer.valueGeneric); | |
1159 assert(answerExportedResources_ != NULL); | |
1160 answerExportedResources_->push_back | |
1161 (ExportedResource(exported.seq, | |
1162 Plugins::Convert(exported.resourceType), | |
1163 exported.publicId, | |
1164 exported.modality, | |
1165 exported.date, | |
1166 exported.patientId, | |
1167 exported.studyInstanceUid, | |
1168 exported.seriesInstanceUid, | |
1169 exported.sopInstanceUid)); | |
1170 } | |
1171 | |
1172 break; | |
1173 } | |
1174 | |
1175 case _OrthancPluginDatabaseAnswerType_MatchingResource: | |
1176 { | |
1177 const OrthancPluginMatchingResource& match = | |
1178 *reinterpret_cast<const OrthancPluginMatchingResource*>(answer.valueGeneric); | |
1179 | |
1180 if (match.resourceId == NULL) | |
1181 { | |
1182 throw OrthancException(ErrorCode_DatabasePlugin); | |
1183 } | |
1184 | |
1185 assert(answerMatchingResources_ != NULL); | |
1186 answerMatchingResources_->push_back(match.resourceId); | |
1187 | |
1188 if (answerMatchingInstances_ != NULL) | |
1189 { | |
1190 if (match.someInstanceId == NULL) | |
1191 { | |
1192 throw OrthancException(ErrorCode_DatabasePlugin); | |
1193 } | |
1194 | |
1195 answerMatchingInstances_->push_back(match.someInstanceId); | |
1196 } | |
1197 | |
1198 break; | |
1199 } | |
1200 | |
1201 case _OrthancPluginDatabaseAnswerType_Metadata: | |
1202 { | |
1203 const OrthancPluginResourcesContentMetadata& metadata = | |
1204 *reinterpret_cast<const OrthancPluginResourcesContentMetadata*>(answer.valueGeneric); | |
1205 | |
1206 MetadataType type = static_cast<MetadataType>(metadata.metadata); | |
1207 | |
1208 if (metadata.value == NULL) | |
1209 { | |
1210 throw OrthancException(ErrorCode_DatabasePlugin); | |
1211 } | |
1212 | |
1213 assert(answerMetadata_ != NULL && | |
1214 answerMetadata_->find(type) == answerMetadata_->end()); | |
1215 (*answerMetadata_) [type] = metadata.value; | |
1216 break; | |
1217 } | |
1218 | |
1219 default: | |
1220 throw OrthancException(ErrorCode_DatabasePlugin, | |
1221 "Unhandled type of answer for custom index plugin: " + | |
1222 boost::lexical_cast<std::string>(answer.type)); | |
1223 } | |
1224 } | |
1225 | |
1226 | |
1227 bool OrthancPluginDatabase::IsDiskSizeAbove(uint64_t threshold) | |
1228 { | |
1229 if (fastGetTotalSize_) | |
1230 { | |
1231 return GetTotalCompressedSize() > threshold; | |
1232 } | |
1233 else | |
1234 { | |
1235 assert(GetTotalCompressedSize() == currentDiskSize_); | |
1236 return currentDiskSize_ > threshold; | |
1237 } | |
1238 } | |
1239 | |
1240 | |
1241 void OrthancPluginDatabase::ApplyLookupResources(std::list<std::string>& resourcesId, | |
1242 std::list<std::string>* instancesId, | |
1243 const std::vector<DatabaseConstraint>& lookup, | |
1244 ResourceType queryLevel, | |
1245 size_t limit) | |
1246 { | |
1247 if (extensions_.lookupResources == NULL) | |
1248 { | |
1249 // Fallback to compatibility mode | |
1250 ILookupResources::Apply | |
1251 (*this, *this, resourcesId, instancesId, lookup, queryLevel, limit); | |
1252 } | |
1253 else | |
1254 { | |
1255 std::vector<OrthancPluginDatabaseConstraint> constraints; | |
1256 std::vector< std::vector<const char*> > constraintsValues; | |
1257 | |
1258 constraints.resize(lookup.size()); | |
1259 constraintsValues.resize(lookup.size()); | |
1260 | |
1261 for (size_t i = 0; i < lookup.size(); i++) | |
1262 { | |
1263 lookup[i].EncodeForPlugins(constraints[i], constraintsValues[i]); | |
1264 } | |
1265 | |
1266 ResetAnswers(); | |
1267 answerMatchingResources_ = &resourcesId; | |
1268 answerMatchingInstances_ = instancesId; | |
1269 | |
1270 CheckSuccess(extensions_.lookupResources(GetContext(), payload_, lookup.size(), | |
1271 (lookup.empty() ? NULL : &constraints[0]), | |
1272 Plugins::Convert(queryLevel), | |
1273 limit, (instancesId == NULL ? 0 : 1))); | |
1274 } | |
1275 } | |
1276 | |
1277 | |
1278 bool OrthancPluginDatabase::CreateInstance( | |
1279 IDatabaseWrapper::CreateInstanceResult& result, | |
1280 int64_t& instanceId, | |
1281 const std::string& patient, | |
1282 const std::string& study, | |
1283 const std::string& series, | |
1284 const std::string& instance) | |
1285 { | |
1286 if (extensions_.createInstance == NULL) | |
1287 { | |
1288 // Fallback to compatibility mode | |
1289 return ICreateInstance::Apply | |
1290 (*this, result, instanceId, patient, study, series, instance); | |
1291 } | |
1292 else | |
1293 { | |
1294 OrthancPluginCreateInstanceResult output; | |
1295 memset(&output, 0, sizeof(output)); | |
1296 | |
1297 CheckSuccess(extensions_.createInstance(&output, payload_, patient.c_str(), | |
1298 study.c_str(), series.c_str(), instance.c_str())); | |
1299 | |
1300 instanceId = output.instanceId; | |
1301 | |
1302 if (output.isNewInstance) | |
1303 { | |
1304 result.isNewPatient_ = output.isNewPatient; | |
1305 result.isNewStudy_ = output.isNewStudy; | |
1306 result.isNewSeries_ = output.isNewSeries; | |
1307 result.patientId_ = output.patientId; | |
1308 result.studyId_ = output.studyId; | |
1309 result.seriesId_ = output.seriesId; | |
1310 return true; | |
1311 } | |
1312 else | |
1313 { | |
1314 return false; | |
1315 } | |
1316 } | |
1317 } | |
1318 | |
1319 | |
1320 void OrthancPluginDatabase::LookupIdentifier(std::list<int64_t>& result, | |
1321 ResourceType level, | |
1322 const DicomTag& tag, | |
1323 Compatibility::IdentifierConstraintType type, | |
1324 const std::string& value) | |
1325 { | |
1326 if (extensions_.lookupIdentifier3 == NULL) | |
1327 { | |
1328 throw OrthancException(ErrorCode_DatabasePlugin, | |
1329 "The database plugin does not implement the mandatory LookupIdentifier3() extension"); | |
1330 } | |
1331 | |
1332 OrthancPluginDicomTag tmp; | |
1333 tmp.group = tag.GetGroup(); | |
1334 tmp.element = tag.GetElement(); | |
1335 tmp.value = value.c_str(); | |
1336 | |
1337 ResetAnswers(); | |
1338 CheckSuccess(extensions_.lookupIdentifier3(GetContext(), payload_, Plugins::Convert(level), | |
1339 &tmp, Compatibility::Convert(type))); | |
1340 ForwardAnswers(result); | |
1341 } | |
1342 | |
1343 | |
1344 void OrthancPluginDatabase::LookupIdentifierRange(std::list<int64_t>& result, | |
1345 ResourceType level, | |
1346 const DicomTag& tag, | |
1347 const std::string& start, | |
1348 const std::string& end) | |
1349 { | |
1350 if (extensions_.lookupIdentifierRange == NULL) | |
1351 { | |
1352 // Default implementation, for plugins using Orthanc SDK <= 1.3.2 | |
1353 | |
1354 LookupIdentifier(result, level, tag, Compatibility::IdentifierConstraintType_GreaterOrEqual, start); | |
1355 | |
1356 std::list<int64_t> b; | |
1357 LookupIdentifier(result, level, tag, Compatibility::IdentifierConstraintType_SmallerOrEqual, end); | |
1358 | |
1359 result.splice(result.end(), b); | |
1360 } | |
1361 else | |
1362 { | |
1363 ResetAnswers(); | |
1364 CheckSuccess(extensions_.lookupIdentifierRange(GetContext(), payload_, Plugins::Convert(level), | |
1365 tag.GetGroup(), tag.GetElement(), | |
1366 start.c_str(), end.c_str())); | |
1367 ForwardAnswers(result); | |
1368 } | |
1369 } | |
1370 | |
1371 | |
1372 void OrthancPluginDatabase::SetResourcesContent(const Orthanc::ResourcesContent& content) | |
1373 { | |
1374 if (extensions_.setResourcesContent == NULL) | |
1375 { | |
1376 ISetResourcesContent::Apply(*this, content); | |
1377 } | |
1378 else | |
1379 { | |
1380 std::vector<OrthancPluginResourcesContentTags> identifierTags; | |
1381 std::vector<OrthancPluginResourcesContentTags> mainDicomTags; | |
1382 std::vector<OrthancPluginResourcesContentMetadata> metadata; | |
1383 | |
1384 identifierTags.reserve(content.GetListTags().size()); | |
1385 mainDicomTags.reserve(content.GetListTags().size()); | |
1386 metadata.reserve(content.GetListMetadata().size()); | |
1387 | |
1388 for (ResourcesContent::ListTags::const_iterator | |
1389 it = content.GetListTags().begin(); it != content.GetListTags().end(); ++it) | |
1390 { | |
1391 OrthancPluginResourcesContentTags tmp; | |
1392 tmp.resource = it->resourceId_; | |
1393 tmp.group = it->tag_.GetGroup(); | |
1394 tmp.element = it->tag_.GetElement(); | |
1395 tmp.value = it->value_.c_str(); | |
1396 | |
1397 if (it->isIdentifier_) | |
1398 { | |
1399 identifierTags.push_back(tmp); | |
1400 } | |
1401 else | |
1402 { | |
1403 mainDicomTags.push_back(tmp); | |
1404 } | |
1405 } | |
1406 | |
1407 for (ResourcesContent::ListMetadata::const_iterator | |
1408 it = content.GetListMetadata().begin(); it != content.GetListMetadata().end(); ++it) | |
1409 { | |
1410 OrthancPluginResourcesContentMetadata tmp; | |
1411 tmp.resource = it->resourceId_; | |
1412 tmp.metadata = it->metadata_; | |
1413 tmp.value = it->value_.c_str(); | |
1414 metadata.push_back(tmp); | |
1415 } | |
1416 | |
1417 assert(identifierTags.size() + mainDicomTags.size() == content.GetListTags().size() && | |
1418 metadata.size() == content.GetListMetadata().size()); | |
1419 | |
1420 CheckSuccess(extensions_.setResourcesContent( | |
1421 payload_, | |
1422 identifierTags.size(), | |
1423 (identifierTags.empty() ? NULL : &identifierTags[0]), | |
1424 mainDicomTags.size(), | |
1425 (mainDicomTags.empty() ? NULL : &mainDicomTags[0]), | |
1426 metadata.size(), | |
1427 (metadata.empty() ? NULL : &metadata[0]))); | |
1428 } | |
1429 } | |
1430 | |
1431 | |
1432 | |
1433 void OrthancPluginDatabase::GetChildrenMetadata(std::list<std::string>& target, | |
1434 int64_t resourceId, | |
1435 MetadataType metadata) | |
1436 { | |
1437 if (extensions_.getChildrenMetadata == NULL) | |
1438 { | |
1439 IGetChildrenMetadata::Apply(*this, target, resourceId, metadata); | |
1440 } | |
1441 else | |
1442 { | |
1443 ResetAnswers(); | |
1444 CheckSuccess(extensions_.getChildrenMetadata | |
1445 (GetContext(), payload_, resourceId, static_cast<int32_t>(metadata))); | |
1446 ForwardAnswers(target); | |
1447 } | |
1448 } | |
1449 | |
1450 | |
1451 int64_t OrthancPluginDatabase::GetLastChangeIndex() | |
1452 { | |
1453 if (extensions_.getLastChangeIndex == NULL) | |
1454 { | |
1455 // This was the default behavior in Orthanc <= 1.5.1 | |
1456 // https://groups.google.com/d/msg/orthanc-users/QhzB6vxYeZ0/YxabgqpfBAAJ | |
1457 return 0; | |
1458 } | |
1459 else | |
1460 { | |
1461 int64_t result = 0; | |
1462 CheckSuccess(extensions_.getLastChangeIndex(&result, payload_)); | |
1463 return result; | |
1464 } | |
1465 } | |
1466 | |
1467 | |
1468 void OrthancPluginDatabase::TagMostRecentPatient(int64_t patient) | |
1469 { | |
1470 if (extensions_.tagMostRecentPatient != NULL) | |
1471 { | |
1472 CheckSuccess(extensions_.tagMostRecentPatient(payload_, patient)); | |
1473 } | |
1474 } | |
1475 | |
1476 | |
1477 bool OrthancPluginDatabase::LookupResourceAndParent(int64_t& id, | |
1478 ResourceType& type, | |
1479 std::string& parentPublicId, | |
1480 const std::string& publicId) | |
1481 { | |
1482 if (extensions_.lookupResourceAndParent == NULL) | |
1483 { | |
1484 return ILookupResourceAndParent::Apply(*this, id, type, parentPublicId, publicId); | |
1485 } | |
1486 else | |
1487 { | |
1488 std::list<std::string> parent; | |
1489 | |
1490 uint8_t isExisting; | |
1491 OrthancPluginResourceType pluginType = OrthancPluginResourceType_Patient; | |
1492 | |
1493 ResetAnswers(); | |
1494 CheckSuccess(extensions_.lookupResourceAndParent | |
1495 (GetContext(), &isExisting, &id, &pluginType, payload_, publicId.c_str())); | |
1496 ForwardAnswers(parent); | |
1497 | |
1498 if (isExisting) | |
1499 { | |
1500 type = Plugins::Convert(pluginType); | |
1501 | |
1502 if (parent.empty()) | |
1503 { | |
1504 if (type != ResourceType_Patient) | |
1505 { | |
1506 throw OrthancException(ErrorCode_DatabasePlugin); | |
1507 } | |
1508 } | |
1509 else if (parent.size() == 1) | |
1510 { | |
1511 if ((type != ResourceType_Study && | |
1512 type != ResourceType_Series && | |
1513 type != ResourceType_Instance) || | |
1514 parent.front().empty()) | |
1515 { | |
1516 throw OrthancException(ErrorCode_DatabasePlugin); | |
1517 } | |
1518 | |
1519 parentPublicId = parent.front(); | |
1520 } | |
1521 else | |
1522 { | |
1523 throw OrthancException(ErrorCode_DatabasePlugin); | |
1524 } | |
1525 | |
1526 return true; | |
1527 } | |
1528 else | |
1529 { | |
1530 return false; | |
1531 } | |
1532 } | |
1533 } | |
1534 } |