comparison Plugins/Engine/OrthancPluginDatabase.cpp @ 1309:8f4487d8f79e db-changes

new files for custom database back-end
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 11 Feb 2015 10:36:22 +0100
parents
children 01be1432bda9
comparison
equal deleted inserted replaced
1308:f7966e9950e4 1309:8f4487d8f79e
1 /**
2 * Orthanc - A Lightweight, RESTful DICOM Store
3 * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 *
6 * This program is free software: you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * In addition, as a special exception, the copyright holders of this
12 * program give permission to link the code of its release with the
13 * OpenSSL project's "OpenSSL" library (or with modified versions of it
14 * that use the same license as the "OpenSSL" library), and distribute
15 * the linked executables. You must obey the GNU General Public License
16 * in all respects for all of the code used other than "OpenSSL". If you
17 * modify file(s) with this exception, you may extend this exception to
18 * your version of the file(s), but you are not obligated to do so. If
19 * you do not wish to do so, delete this exception statement from your
20 * version. If you delete this exception statement from all source files
21 * in the program, then also delete it here.
22 *
23 * This program is distributed in the hope that it will be useful, but
24 * WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 * General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program. If not, see <http://www.gnu.org/licenses/>.
30 **/
31
32
33 #include "OrthancPluginDatabase.h"
34
35 #include "../../Core/OrthancException.h"
36
37 #include <cassert>
38 #include <glog/logging.h>
39
40 namespace Orthanc
41 {
42 static OrthancPluginResourceType Convert(ResourceType type)
43 {
44 switch (type)
45 {
46 case ResourceType_Patient:
47 return OrthancPluginResourceType_Patient;
48
49 case ResourceType_Study:
50 return OrthancPluginResourceType_Study;
51
52 case ResourceType_Series:
53 return OrthancPluginResourceType_Series;
54
55 case ResourceType_Instance:
56 return OrthancPluginResourceType_Instance;
57
58 default:
59 throw OrthancException(ErrorCode_InternalError);
60 }
61 }
62
63
64 static ResourceType Convert(OrthancPluginResourceType type)
65 {
66 switch (type)
67 {
68 case OrthancPluginResourceType_Patient:
69 return ResourceType_Patient;
70
71 case OrthancPluginResourceType_Study:
72 return ResourceType_Study;
73
74 case OrthancPluginResourceType_Series:
75 return ResourceType_Series;
76
77 case OrthancPluginResourceType_Instance:
78 return ResourceType_Instance;
79
80 default:
81 throw OrthancException(ErrorCode_InternalError);
82 }
83 }
84
85
86 static FileInfo Convert(const OrthancPluginAttachment& attachment)
87 {
88 return FileInfo(attachment.uuid,
89 static_cast<FileContentType>(attachment.contentType),
90 attachment.uncompressedSize,
91 attachment.uncompressedHash,
92 static_cast<CompressionType>(attachment.compressionType),
93 attachment.compressedSize,
94 attachment.compressedHash);
95 }
96
97
98 void OrthancPluginDatabase::ResetAnswers()
99 {
100 type_ = _OrthancPluginDatabaseAnswerType_None;
101
102 answerDicomMap_ = NULL;
103 answerChanges_ = NULL;
104 answerExportedResources_ = NULL;
105 answerDone_ = NULL;
106 }
107
108
109 void OrthancPluginDatabase::ForwardAnswers(std::list<int64_t>& target)
110 {
111 if (type_ != _OrthancPluginDatabaseAnswerType_None &&
112 type_ != _OrthancPluginDatabaseAnswerType_Int64)
113 {
114 throw OrthancException(ErrorCode_Plugin);
115 }
116
117 target.clear();
118
119 if (type_ == _OrthancPluginDatabaseAnswerType_Int64)
120 {
121 for (std::list<int64_t>::const_iterator
122 it = answerInt64_.begin(); it != answerInt64_.end(); it++)
123 {
124 target.push_back(*it);
125 }
126 }
127 }
128
129
130 void OrthancPluginDatabase::ForwardAnswers(std::list<std::string>& target)
131 {
132 if (type_ != _OrthancPluginDatabaseAnswerType_None &&
133 type_ != _OrthancPluginDatabaseAnswerType_String)
134 {
135 throw OrthancException(ErrorCode_Plugin);
136 }
137
138 target.clear();
139
140 if (type_ == _OrthancPluginDatabaseAnswerType_String)
141 {
142 for (std::list<std::string>::const_iterator
143 it = answerStrings_.begin(); it != answerStrings_.end(); it++)
144 {
145 target.push_back(*it);
146 }
147 }
148 }
149
150
151 bool OrthancPluginDatabase::ForwardSingleAnswer(std::string& target)
152 {
153 if (type_ == _OrthancPluginDatabaseAnswerType_None)
154 {
155 return false;
156 }
157 else if (type_ == _OrthancPluginDatabaseAnswerType_String &&
158 answerStrings_.size() == 1)
159 {
160 target = answerStrings_.front();
161 return true;
162 }
163 else
164 {
165 throw OrthancException(ErrorCode_Plugin);
166 }
167 }
168
169
170 bool OrthancPluginDatabase::ForwardSingleAnswer(int64_t& target)
171 {
172 if (type_ == _OrthancPluginDatabaseAnswerType_None)
173 {
174 return false;
175 }
176 else if (type_ == _OrthancPluginDatabaseAnswerType_Int64 &&
177 answerInt64_.size() == 1)
178 {
179 target = answerInt64_.front();
180 return true;
181 }
182 else
183 {
184 throw OrthancException(ErrorCode_Plugin);
185 }
186 }
187
188
189 void OrthancPluginDatabase::AddAttachment(int64_t id,
190 const FileInfo& attachment)
191 {
192 OrthancPluginAttachment tmp;
193 tmp.uuid = attachment.GetUuid().c_str();
194 tmp.contentType = static_cast<int32_t>(attachment.GetContentType());
195 tmp.uncompressedSize = attachment.GetUncompressedSize();
196 tmp.uncompressedHash = attachment.GetUncompressedMD5().c_str();
197 tmp.compressionType = static_cast<int32_t>(attachment.GetCompressionType());
198 tmp.compressedSize = attachment.GetCompressedSize();
199 tmp.compressedHash = attachment.GetCompressedMD5().c_str();
200
201 if (backend_.addAttachment(payload_, id, &tmp) != 0)
202 {
203 throw OrthancException(ErrorCode_Plugin);
204 }
205 }
206
207
208 void OrthancPluginDatabase::AttachChild(int64_t parent,
209 int64_t child)
210 {
211 if (backend_.attachChild(payload_, parent, child) != 0)
212 {
213 throw OrthancException(ErrorCode_Plugin);
214 }
215 }
216
217
218 void OrthancPluginDatabase::ClearChanges()
219 {
220 if (backend_.clearChanges(payload_) != 0)
221 {
222 throw OrthancException(ErrorCode_Plugin);
223 }
224 }
225
226
227 void OrthancPluginDatabase::ClearExportedResources()
228 {
229 if (backend_.clearExportedResources(payload_) != 0)
230 {
231 throw OrthancException(ErrorCode_Plugin);
232 }
233 }
234
235
236 int64_t OrthancPluginDatabase::CreateResource(const std::string& publicId,
237 ResourceType type)
238 {
239 int64_t id;
240
241 if (backend_.createResource(&id, payload_, publicId.c_str(), Convert(type)) != 0)
242 {
243 throw OrthancException(ErrorCode_Plugin);
244 }
245
246 return id;
247 }
248
249
250 void OrthancPluginDatabase::DeleteAttachment(int64_t id,
251 FileContentType attachment)
252 {
253 if (backend_.deleteAttachment(payload_, id, static_cast<int32_t>(attachment)) != 0)
254 {
255 throw OrthancException(ErrorCode_Plugin);
256 }
257 }
258
259
260 void OrthancPluginDatabase::DeleteMetadata(int64_t id,
261 MetadataType type)
262 {
263 if (backend_.deleteMetadata(payload_, id, static_cast<int32_t>(type)) != 0)
264 {
265 throw OrthancException(ErrorCode_Plugin);
266 }
267 }
268
269
270 void OrthancPluginDatabase::DeleteResource(int64_t id)
271 {
272 if (backend_.deleteResource(payload_, id) != 0)
273 {
274 throw OrthancException(ErrorCode_Plugin);
275 }
276 }
277
278
279 void OrthancPluginDatabase::GetAllMetadata(std::map<MetadataType, std::string>& target,
280 int64_t id)
281 {
282 std::list<MetadataType> metadata;
283 ListAvailableMetadata(metadata, id);
284
285 target.clear();
286
287 for (std::list<MetadataType>::const_iterator
288 it = metadata.begin(); it != metadata.end(); it++)
289 {
290 std::string value;
291 if (!LookupMetadata(value, id, *it))
292 {
293 throw OrthancException(ErrorCode_Plugin);
294 }
295
296 target[*it] = value;
297 }
298 }
299
300
301 void OrthancPluginDatabase::GetAllPublicIds(std::list<std::string>& target,
302 ResourceType resourceType)
303 {
304 ResetAnswers();
305
306 if (backend_.getAllPublicIds(GetContext(), payload_, Convert(resourceType)) != 0)
307 {
308 throw OrthancException(ErrorCode_Plugin);
309 }
310
311 ForwardAnswers(target);
312 }
313
314
315
316 void OrthancPluginDatabase::GetChanges(std::list<ServerIndexChange>& target /*out*/,
317 bool& done /*out*/,
318 int64_t since,
319 uint32_t maxResults)
320 {
321 ResetAnswers();
322 answerChanges_ = &target;
323 answerDone_ = &done;
324 done = false;
325
326 if (backend_.getChanges(GetContext(), payload_, since, maxResults) != 0)
327 {
328 throw OrthancException(ErrorCode_Plugin);
329 }
330 }
331
332
333 void OrthancPluginDatabase::GetChildrenInternalId(std::list<int64_t>& target,
334 int64_t id)
335 {
336 ResetAnswers();
337
338 if (backend_.getChildrenInternalId(GetContext(), payload_, id) != 0)
339 {
340 throw OrthancException(ErrorCode_Plugin);
341 }
342
343 ForwardAnswers(target);
344 }
345
346
347 void OrthancPluginDatabase::GetChildrenPublicId(std::list<std::string>& target,
348 int64_t id)
349 {
350 ResetAnswers();
351
352 if (backend_.getChildrenPublicId(GetContext(), payload_, id) != 0)
353 {
354 throw OrthancException(ErrorCode_Plugin);
355 }
356
357 ForwardAnswers(target);
358 }
359
360
361 void OrthancPluginDatabase::GetExportedResources(std::list<ExportedResource>& target /*out*/,
362 bool& done /*out*/,
363 int64_t since,
364 uint32_t maxResults)
365 {
366 ResetAnswers();
367 answerExportedResources_ = &target;
368 answerDone_ = &done;
369 done = false;
370
371 if (backend_.getExportedResources(GetContext(), payload_, since, maxResults) != 0)
372 {
373 throw OrthancException(ErrorCode_Plugin);
374 }
375 }
376
377
378 void OrthancPluginDatabase::GetLastChange(std::list<ServerIndexChange>& target /*out*/)
379 {
380 bool ignored = false;
381
382 ResetAnswers();
383 answerChanges_ = &target;
384 answerDone_ = &ignored;
385
386 if (backend_.getLastChange(GetContext(), payload_) != 0)
387 {
388 throw OrthancException(ErrorCode_Plugin);
389 }
390 }
391
392
393 void OrthancPluginDatabase::GetLastExportedResource(std::list<ExportedResource>& target /*out*/)
394 {
395 bool ignored = false;
396
397 ResetAnswers();
398 answerExportedResources_ = &target;
399 answerDone_ = &ignored;
400
401 if (backend_.getLastExportedResource(GetContext(), payload_) != 0)
402 {
403 throw OrthancException(ErrorCode_Plugin);
404 }
405 }
406
407
408 void OrthancPluginDatabase::GetMainDicomTags(DicomMap& map,
409 int64_t id)
410 {
411 ResetAnswers();
412 answerDicomMap_ = &map;
413
414 if (backend_.getMainDicomTags(GetContext(), payload_, id) != 0)
415 {
416 throw OrthancException(ErrorCode_Plugin);
417 }
418 }
419
420
421 std::string OrthancPluginDatabase::GetPublicId(int64_t resourceId)
422 {
423 ResetAnswers();
424 std::string s;
425
426 if (backend_.getPublicId(GetContext(), payload_, resourceId) != 0 ||
427 !ForwardSingleAnswer(s))
428 {
429 throw OrthancException(ErrorCode_Plugin);
430 }
431
432 return s;
433 }
434
435
436 uint64_t OrthancPluginDatabase::GetResourceCount(ResourceType resourceType)
437 {
438 uint64_t count;
439
440 if (backend_.getResourceCount(&count, payload_, Convert(resourceType)) != 0)
441 {
442 throw OrthancException(ErrorCode_Plugin);
443 }
444
445 return count;
446 }
447
448
449 ResourceType OrthancPluginDatabase::GetResourceType(int64_t resourceId)
450 {
451 OrthancPluginResourceType type;
452
453 if (backend_.getResourceType(&type, payload_, resourceId) != 0)
454 {
455 throw OrthancException(ErrorCode_Plugin);
456 }
457
458 return Convert(type);
459 }
460
461
462 uint64_t OrthancPluginDatabase::GetTotalCompressedSize()
463 {
464 uint64_t size;
465
466 if (backend_.getTotalCompressedSize(&size, payload_) != 0)
467 {
468 throw OrthancException(ErrorCode_Plugin);
469 }
470
471 return size;
472 }
473
474
475 uint64_t OrthancPluginDatabase::GetTotalUncompressedSize()
476 {
477 uint64_t size;
478
479 if (backend_.getTotalUncompressedSize(&size, payload_) != 0)
480 {
481 throw OrthancException(ErrorCode_Plugin);
482 }
483
484 return size;
485 }
486
487
488 bool OrthancPluginDatabase::IsExistingResource(int64_t internalId)
489 {
490 int32_t existing;
491
492 if (backend_.isExistingResource(&existing, payload_, internalId) != 0)
493 {
494 throw OrthancException(ErrorCode_Plugin);
495 }
496
497 return existing;
498 }
499
500
501 bool OrthancPluginDatabase::IsProtectedPatient(int64_t internalId)
502 {
503 int32_t isProtected;
504
505 if (backend_.isProtectedPatient(&isProtected, payload_, internalId) != 0)
506 {
507 throw OrthancException(ErrorCode_Plugin);
508 }
509
510 return isProtected;
511 }
512
513
514 void OrthancPluginDatabase::ListAvailableMetadata(std::list<MetadataType>& target,
515 int64_t id)
516 {
517 ResetAnswers();
518
519 if (backend_.listAvailableMetadata(GetContext(), payload_, id) != 0)
520 {
521 throw OrthancException(ErrorCode_Plugin);
522 }
523
524 if (type_ != _OrthancPluginDatabaseAnswerType_None &&
525 type_ != _OrthancPluginDatabaseAnswerType_Int32)
526 {
527 throw OrthancException(ErrorCode_Plugin);
528 }
529
530 target.clear();
531
532 if (type_ == _OrthancPluginDatabaseAnswerType_Int32)
533 {
534 for (std::list<int32_t>::const_iterator
535 it = answerInt32_.begin(); it != answerInt32_.end(); it++)
536 {
537 target.push_back(static_cast<MetadataType>(*it));
538 }
539 }
540 }
541
542
543 void OrthancPluginDatabase::ListAvailableAttachments(std::list<FileContentType>& target,
544 int64_t id)
545 {
546 ResetAnswers();
547
548 if (backend_.listAvailableAttachments(GetContext(), payload_, id) != 0)
549 {
550 throw OrthancException(ErrorCode_Plugin);
551 }
552
553 if (type_ != _OrthancPluginDatabaseAnswerType_None &&
554 type_ != _OrthancPluginDatabaseAnswerType_Int32)
555 {
556 throw OrthancException(ErrorCode_Plugin);
557 }
558
559 target.clear();
560
561 if (type_ == _OrthancPluginDatabaseAnswerType_Int32)
562 {
563 for (std::list<int32_t>::const_iterator
564 it = answerInt32_.begin(); it != answerInt32_.end(); it++)
565 {
566 target.push_back(static_cast<FileContentType>(*it));
567 }
568 }
569 }
570
571
572 void OrthancPluginDatabase::LogChange(int64_t internalId,
573 const ServerIndexChange& change)
574 {
575 OrthancPluginChange tmp;
576 tmp.seq = change.GetSeq();
577 tmp.changeType = static_cast<int32_t>(change.GetChangeType());
578 tmp.resourceType = Convert(change.GetResourceType());
579 tmp.publicId = change.GetPublicId().c_str();
580 tmp.date = change.GetDate().c_str();
581
582 if (backend_.logChange(payload_, &tmp) != 0)
583 {
584 throw OrthancException(ErrorCode_Plugin);
585 }
586 }
587
588
589 void OrthancPluginDatabase::LogExportedResource(const ExportedResource& resource)
590 {
591 OrthancPluginExportedResource tmp;
592 tmp.seq = resource.GetSeq();
593 tmp.resourceType = Convert(resource.GetResourceType());
594 tmp.publicId = resource.GetPublicId().c_str();
595 tmp.modality = resource.GetModality().c_str();
596 tmp.date = resource.GetDate().c_str();
597 tmp.patientId = resource.GetPatientId().c_str();
598 tmp.studyInstanceUid = resource.GetStudyInstanceUid().c_str();
599 tmp.seriesInstanceUid = resource.GetSeriesInstanceUid().c_str();
600 tmp.sopInstanceUid = resource.GetSopInstanceUid().c_str();
601
602 if (backend_.logExportedResource(payload_, &tmp) != 0)
603 {
604 throw OrthancException(ErrorCode_Plugin);
605 }
606 }
607
608
609 bool OrthancPluginDatabase::LookupAttachment(FileInfo& attachment,
610 int64_t id,
611 FileContentType contentType)
612 {
613 ResetAnswers();
614
615 if (backend_.lookupAttachment(GetContext(), payload_, id, static_cast<int32_t>(contentType)))
616 {
617 throw OrthancException(ErrorCode_Plugin);
618 }
619
620 if (type_ == _OrthancPluginDatabaseAnswerType_None)
621 {
622 return false;
623 }
624 else if (type_ == _OrthancPluginDatabaseAnswerType_Attachment &&
625 answerAttachments_.size() == 1)
626 {
627 attachment = answerAttachments_.front();
628 return true;
629 }
630 else
631 {
632 throw OrthancException(ErrorCode_Plugin);
633 }
634 }
635
636
637 bool OrthancPluginDatabase::LookupGlobalProperty(std::string& target,
638 GlobalProperty property)
639 {
640 ResetAnswers();
641
642 if (backend_.lookupGlobalProperty(GetContext(), payload_,
643 static_cast<int32_t>(property)))
644 {
645 throw OrthancException(ErrorCode_Plugin);
646 }
647
648 return ForwardSingleAnswer(target);
649 }
650
651
652 void OrthancPluginDatabase::LookupIdentifier(std::list<int64_t>& target,
653 const DicomTag& tag,
654 const std::string& value)
655 {
656 ResetAnswers();
657
658 OrthancPluginDicomTag tmp;
659 tmp.group = tag.GetGroup();
660 tmp.element = tag.GetElement();
661 tmp.value = value.c_str();
662
663 if (backend_.lookupIdentifier(GetContext(), payload_, &tmp) != 0)
664 {
665 throw OrthancException(ErrorCode_Plugin);
666 }
667
668 ForwardAnswers(target);
669 }
670
671
672 void OrthancPluginDatabase::LookupIdentifier(std::list<int64_t>& target,
673 const std::string& value)
674 {
675 ResetAnswers();
676
677 if (backend_.lookupIdentifier2(GetContext(), payload_, value.c_str()) != 0)
678 {
679 throw OrthancException(ErrorCode_Plugin);
680 }
681
682 ForwardAnswers(target);
683 }
684
685
686 bool OrthancPluginDatabase::LookupMetadata(std::string& target,
687 int64_t id,
688 MetadataType type)
689 {
690 ResetAnswers();
691
692 if (backend_.lookupMetadata(GetContext(), payload_, id, static_cast<int32_t>(type)))
693 {
694 throw OrthancException(ErrorCode_Plugin);
695 }
696
697 return ForwardSingleAnswer(target);
698 }
699
700
701 bool OrthancPluginDatabase::LookupParent(int64_t& parentId,
702 int64_t resourceId)
703 {
704 ResetAnswers();
705
706 if (backend_.lookupParent(GetContext(), payload_, resourceId))
707 {
708 throw OrthancException(ErrorCode_Plugin);
709 }
710
711 return ForwardSingleAnswer(parentId);
712 }
713
714
715 bool OrthancPluginDatabase::LookupResource(int64_t& id,
716 ResourceType& type,
717 const std::string& publicId)
718 {
719 ResetAnswers();
720
721 if (backend_.lookupResource(GetContext(), payload_, publicId.c_str()))
722 {
723 throw OrthancException(ErrorCode_Plugin);
724 }
725
726 if (type_ == _OrthancPluginDatabaseAnswerType_None)
727 {
728 return false;
729 }
730 else if (type_ == _OrthancPluginDatabaseAnswerType_Resource &&
731 answerResources_.size() == 1)
732 {
733 id = answerResources_.front().first;
734 type = answerResources_.front().second;
735 return true;
736 }
737 else
738 {
739 throw OrthancException(ErrorCode_Plugin);
740 }
741 }
742
743
744 bool OrthancPluginDatabase::SelectPatientToRecycle(int64_t& internalId)
745 {
746 ResetAnswers();
747
748 if (backend_.selectPatientToRecycle(GetContext(), payload_))
749 {
750 throw OrthancException(ErrorCode_Plugin);
751 }
752
753 return ForwardSingleAnswer(internalId);
754 }
755
756
757 bool OrthancPluginDatabase::SelectPatientToRecycle(int64_t& internalId,
758 int64_t patientIdToAvoid)
759 {
760 ResetAnswers();
761
762 if (backend_.selectPatientToRecycle2(GetContext(), payload_, patientIdToAvoid))
763 {
764 throw OrthancException(ErrorCode_Plugin);
765 }
766
767 return ForwardSingleAnswer(internalId);
768 }
769
770
771 void OrthancPluginDatabase::SetGlobalProperty(GlobalProperty property,
772 const std::string& value)
773 {
774 if (backend_.setGlobalProperty(payload_, static_cast<int32_t>(property),
775 value.c_str()) != 0)
776 {
777 throw OrthancException(ErrorCode_Plugin);
778 }
779 }
780
781
782 void OrthancPluginDatabase::SetMainDicomTag(int64_t id,
783 const DicomTag& tag,
784 const std::string& value)
785 {
786 int32_t status;
787 OrthancPluginDicomTag tmp;
788 tmp.group = tag.GetGroup();
789 tmp.element = tag.GetElement();
790 tmp.value = value.c_str();
791
792 if (tag.IsIdentifier())
793 {
794 status = backend_.setIdentifierTag(payload_, id, &tmp);
795 }
796 else
797 {
798 status = backend_.setMainDicomTag(payload_, id, &tmp);
799 }
800
801 if (status != 0)
802 {
803 throw OrthancException(ErrorCode_Plugin);
804 }
805 }
806
807
808 void OrthancPluginDatabase::SetMetadata(int64_t id,
809 MetadataType type,
810 const std::string& value)
811 {
812 if (backend_.setMetadata(payload_, id, static_cast<int32_t>(type),
813 value.c_str()) != 0)
814 {
815 throw OrthancException(ErrorCode_Plugin);
816 }
817 }
818
819
820 void OrthancPluginDatabase::SetProtectedPatient(int64_t internalId,
821 bool isProtected)
822 {
823 if (backend_.setProtectedPatient(payload_, internalId, isProtected) != 0)
824 {
825 throw OrthancException(ErrorCode_Plugin);
826 }
827 }
828
829
830 class OrthancPluginDatabase::Transaction : public SQLite::ITransaction
831 {
832 private:
833 const OrthancPluginDatabaseBackend& backend_;
834 void* payload_;
835
836 public:
837 Transaction(const OrthancPluginDatabaseBackend& backend,
838 void* payload) :
839 backend_(backend),
840 payload_(payload)
841 {
842 }
843
844 virtual void Begin()
845 {
846 if (backend_.startTransaction(payload_) != 0)
847 {
848 throw OrthancException(ErrorCode_Plugin);
849 }
850 }
851
852 virtual void Rollback()
853 {
854 if (backend_.rollbackTransaction(payload_) != 0)
855 {
856 throw OrthancException(ErrorCode_Plugin);
857 }
858 }
859
860 virtual void Commit()
861 {
862 if (backend_.commitTransaction(payload_) != 0)
863 {
864 throw OrthancException(ErrorCode_Plugin);
865 }
866 }
867 };
868
869
870 SQLite::ITransaction* OrthancPluginDatabase::StartTransaction()
871 {
872 return new Transaction(backend_, payload_);
873 }
874
875
876 static void ProcessEvent(IServerIndexListener& listener,
877 const _OrthancPluginDatabaseAnswer& answer)
878 {
879 switch (answer.type)
880 {
881 case _OrthancPluginDatabaseAnswerType_DeletedAttachment:
882 {
883 const OrthancPluginAttachment& attachment =
884 *reinterpret_cast<const OrthancPluginAttachment*>(answer.valueGeneric);
885 listener.SignalFileDeleted(Convert(attachment));
886 break;
887 }
888
889 case _OrthancPluginDatabaseAnswerType_RemainingAncestor:
890 {
891 ResourceType type = Convert(static_cast<OrthancPluginResourceType>(answer.valueInt32));
892 listener.SignalRemainingAncestor(type, answer.valueString);
893 break;
894 }
895
896 case _OrthancPluginDatabaseAnswerType_DeletedResource:
897 {
898 ResourceType type = Convert(static_cast<OrthancPluginResourceType>(answer.valueInt32));
899 ServerIndexChange change(ChangeType_Deleted, type, answer.valueString);
900 listener.SignalChange(change);
901 break;
902 }
903
904 default:
905 throw OrthancException(ErrorCode_Plugin);
906 }
907 }
908
909
910 void OrthancPluginDatabase::AnswerReceived(const _OrthancPluginDatabaseAnswer& answer)
911 {
912 if (answer.type == _OrthancPluginDatabaseAnswerType_None)
913 {
914 throw OrthancException(ErrorCode_Plugin);
915 }
916
917 if (answer.type == _OrthancPluginDatabaseAnswerType_DeletedAttachment ||
918 answer.type == _OrthancPluginDatabaseAnswerType_DeletedResource ||
919 answer.type == _OrthancPluginDatabaseAnswerType_RemainingAncestor)
920 {
921 assert(listener_ != NULL);
922 ProcessEvent(*listener_, answer);
923 return;
924 }
925
926 if (type_ == _OrthancPluginDatabaseAnswerType_None)
927 {
928 type_ = answer.type;
929
930 switch (type_)
931 {
932 case _OrthancPluginDatabaseAnswerType_Int32:
933 answerInt32_.clear();
934 break;
935
936 case _OrthancPluginDatabaseAnswerType_Int64:
937 answerInt64_.clear();
938 break;
939
940 case _OrthancPluginDatabaseAnswerType_Resource:
941 answerResources_.clear();
942 break;
943
944 case _OrthancPluginDatabaseAnswerType_Attachment:
945 answerAttachments_.clear();
946 break;
947
948 case _OrthancPluginDatabaseAnswerType_String:
949 answerStrings_.clear();
950 break;
951
952 case _OrthancPluginDatabaseAnswerType_DicomTag:
953 assert(answerDicomMap_ != NULL);
954 answerDicomMap_->Clear();
955 break;
956
957 case _OrthancPluginDatabaseAnswerType_Change:
958 assert(answerChanges_ != NULL);
959 answerChanges_->clear();
960 break;
961
962 case _OrthancPluginDatabaseAnswerType_ExportedResource:
963 assert(answerExportedResources_ != NULL);
964 answerExportedResources_->clear();
965 break;
966
967 default:
968 LOG(ERROR) << "Unhandled type of answer for custom index plugin: " << answer.type;
969 throw OrthancException(ErrorCode_Plugin);
970 }
971 }
972 else if (type_ != answer.type)
973 {
974 LOG(ERROR) << "Error in the plugin protocol: Cannot change the answer type";
975 throw OrthancException(ErrorCode_Plugin);
976 }
977
978 switch (answer.type)
979 {
980 case _OrthancPluginDatabaseAnswerType_Int32:
981 {
982 answerInt32_.push_back(answer.valueInt32);
983 break;
984 }
985
986 case _OrthancPluginDatabaseAnswerType_Int64:
987 {
988 answerInt64_.push_back(answer.valueInt64);
989 break;
990 }
991
992 case _OrthancPluginDatabaseAnswerType_Resource:
993 {
994 OrthancPluginResourceType type = static_cast<OrthancPluginResourceType>(answer.valueInt32);
995 answerResources_.push_back(std::make_pair(answer.valueInt64, Convert(type)));
996 break;
997 }
998
999 case _OrthancPluginDatabaseAnswerType_Attachment:
1000 {
1001 const OrthancPluginAttachment& attachment =
1002 *reinterpret_cast<const OrthancPluginAttachment*>(answer.valueGeneric);
1003
1004 answerAttachments_.push_back(Convert(attachment));
1005 break;
1006 }
1007
1008 case _OrthancPluginDatabaseAnswerType_DicomTag:
1009 {
1010 const OrthancPluginDicomTag& tag = *reinterpret_cast<const OrthancPluginDicomTag*>(answer.valueGeneric);
1011 assert(answerDicomMap_ != NULL);
1012 answerDicomMap_->SetValue(tag.group, tag.element, std::string(tag.value));
1013 break;
1014 }
1015
1016 case _OrthancPluginDatabaseAnswerType_String:
1017 {
1018 if (answer.valueString == NULL)
1019 {
1020 throw OrthancException(ErrorCode_Plugin);
1021 }
1022
1023 if (type_ == _OrthancPluginDatabaseAnswerType_None)
1024 {
1025 type_ = _OrthancPluginDatabaseAnswerType_String;
1026 answerStrings_.clear();
1027 }
1028 else if (type_ != _OrthancPluginDatabaseAnswerType_String)
1029 {
1030 throw OrthancException(ErrorCode_Plugin);
1031 }
1032
1033 answerStrings_.push_back(std::string(answer.valueString));
1034 break;
1035 }
1036
1037 case _OrthancPluginDatabaseAnswerType_Change:
1038 {
1039 assert(answerDone_ != NULL);
1040 if (answer.valueUint32 == 1)
1041 {
1042 *answerDone_ = true;
1043 }
1044 else if (*answerDone_)
1045 {
1046 throw OrthancException(ErrorCode_Plugin);
1047 }
1048 else
1049 {
1050 const OrthancPluginChange& change = *reinterpret_cast<const OrthancPluginChange*>(answer.valueGeneric);
1051 assert(answerChanges_ != NULL);
1052 answerChanges_->push_back
1053 (ServerIndexChange(change.seq,
1054 static_cast<ChangeType>(change.changeType),
1055 Convert(change.resourceType),
1056 change.publicId,
1057 change.date));
1058 }
1059
1060 break;
1061 }
1062
1063 case _OrthancPluginDatabaseAnswerType_ExportedResource:
1064 {
1065 assert(answerDone_ != NULL);
1066 if (answer.valueUint32 == 1)
1067 {
1068 *answerDone_ = true;
1069 }
1070 else if (*answerDone_)
1071 {
1072 throw OrthancException(ErrorCode_Plugin);
1073 }
1074 else
1075 {
1076 const OrthancPluginExportedResource& exported =
1077 *reinterpret_cast<const OrthancPluginExportedResource*>(answer.valueGeneric);
1078 assert(answerExportedResources_ != NULL);
1079 answerExportedResources_->push_back
1080 (ExportedResource(exported.seq,
1081 Convert(exported.resourceType),
1082 exported.publicId,
1083 exported.modality,
1084 exported.date,
1085 exported.patientId,
1086 exported.studyInstanceUid,
1087 exported.seriesInstanceUid,
1088 exported.sopInstanceUid));
1089 }
1090
1091 break;
1092 }
1093
1094 default:
1095 LOG(ERROR) << "Unhandled type of answer for custom index plugin: " << answer.type;
1096 throw OrthancException(ErrorCode_Plugin);
1097 }
1098 }
1099 }