comparison Plugins/Include/OrthancCppDatabasePlugin.h @ 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 3f4297d01a14
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
34 #pragma once
35
36 #include "OrthancCDatabasePlugin.h"
37
38 #include <stdexcept>
39 #include <list>
40 #include <string>
41
42 namespace OrthancPlugins
43 {
44 // This class mimics "boost::noncopyable"
45 class NonCopyable
46 {
47 private:
48 NonCopyable(const NonCopyable&);
49
50 NonCopyable& operator= (const NonCopyable&);
51
52 protected:
53 NonCopyable()
54 {
55 }
56
57 ~NonCopyable()
58 {
59 }
60 };
61
62
63
64 class DatabaseBackendOutput : public NonCopyable
65 {
66 friend class DatabaseBackendAdapter;
67
68 private:
69 enum AllowedAnswers
70 {
71 AllowedAnswers_All,
72 AllowedAnswers_None,
73 AllowedAnswers_Attachment,
74 AllowedAnswers_Change,
75 AllowedAnswers_DicomTag,
76 AllowedAnswers_ExportedResource
77 };
78
79 OrthancPluginContext* context_;
80 OrthancPluginDatabaseContext* database_;
81 AllowedAnswers allowedAnswers_;
82
83 void SetAllowedAnswers(AllowedAnswers allowed)
84 {
85 allowedAnswers_ = allowed;
86 }
87
88 public:
89 DatabaseBackendOutput(OrthancPluginContext* context,
90 OrthancPluginDatabaseContext* database) :
91 context_(context),
92 database_(database),
93 allowedAnswers_(AllowedAnswers_All /* for unit tests */)
94 {
95 }
96
97 void LogError(const std::string& message)
98 {
99 OrthancPluginLogError(context_, message.c_str());
100 }
101
102 void LogWarning(const std::string& message)
103 {
104 OrthancPluginLogWarning(context_, message.c_str());
105 }
106
107 void LogInfo(const std::string& message)
108 {
109 OrthancPluginLogInfo(context_, message.c_str());
110 }
111
112 void SignalDeletedAttachment(const std::string& uuid,
113 int32_t contentType,
114 uint64_t uncompressedSize,
115 const std::string& uncompressedHash,
116 int32_t compressionType,
117 uint64_t compressedSize,
118 const std::string& compressedHash)
119 {
120 OrthancPluginAttachment attachment;
121 attachment.uuid = uuid.c_str();
122 attachment.contentType = contentType;
123 attachment.uncompressedSize = uncompressedSize;
124 attachment.uncompressedHash = uncompressedHash.c_str();
125 attachment.compressionType = compressionType;
126 attachment.compressedSize = compressedSize;
127 attachment.compressedHash = compressedHash.c_str();
128
129 OrthancPluginDatabaseSignalDeletedAttachment(context_, database_, &attachment);
130 }
131
132 void SignalDeletedResource(const std::string& publicId,
133 OrthancPluginResourceType resourceType)
134 {
135 OrthancPluginDatabaseSignalDeletedResource(context_, database_, publicId.c_str(), resourceType);
136 }
137
138 void SignalRemainingAncestor(const std::string& ancestorId,
139 OrthancPluginResourceType ancestorType)
140 {
141 OrthancPluginDatabaseSignalRemainingAncestor(context_, database_, ancestorId.c_str(), ancestorType);
142 }
143
144 void AnswerAttachment(const std::string& uuid,
145 int32_t contentType,
146 uint64_t uncompressedSize,
147 const std::string& uncompressedHash,
148 int32_t compressionType,
149 uint64_t compressedSize,
150 const std::string& compressedHash)
151 {
152 if (allowedAnswers_ != AllowedAnswers_All &&
153 allowedAnswers_ != AllowedAnswers_Attachment)
154 {
155 throw std::runtime_error("Cannot answer with an attachment in the current state");
156 }
157
158 OrthancPluginAttachment attachment;
159 attachment.uuid = uuid.c_str();
160 attachment.contentType = contentType;
161 attachment.uncompressedSize = uncompressedSize;
162 attachment.uncompressedHash = uncompressedHash.c_str();
163 attachment.compressionType = compressionType;
164 attachment.compressedSize = compressedSize;
165 attachment.compressedHash = compressedHash.c_str();
166
167 OrthancPluginDatabaseAnswerAttachment(context_, database_, &attachment);
168 }
169
170 void AnswerChange(int64_t seq,
171 int32_t changeType,
172 OrthancPluginResourceType resourceType,
173 const std::string& publicId,
174 const std::string& date)
175 {
176 if (allowedAnswers_ != AllowedAnswers_All &&
177 allowedAnswers_ != AllowedAnswers_Change)
178 {
179 throw std::runtime_error("Cannot answer with a change in the current state");
180 }
181
182 OrthancPluginChange change;
183 change.seq = seq;
184 change.changeType = changeType;
185 change.resourceType = resourceType;
186 change.publicId = publicId.c_str();
187 change.date = date.c_str();
188
189 OrthancPluginDatabaseAnswerChange(context_, database_, &change);
190 }
191
192 void AnswerDicomTag(uint16_t group,
193 uint16_t element,
194 const std::string& value)
195 {
196 if (allowedAnswers_ != AllowedAnswers_All &&
197 allowedAnswers_ != AllowedAnswers_DicomTag)
198 {
199 throw std::runtime_error("Cannot answer with a DICOM tag in the current state");
200 }
201
202 OrthancPluginDicomTag tag;
203 tag.group = group;
204 tag.element = element;
205 tag.value = value.c_str();
206
207 OrthancPluginDatabaseAnswerDicomTag(context_, database_, &tag);
208 }
209
210 void AnswerExportedResource(int64_t seq,
211 OrthancPluginResourceType resourceType,
212 const std::string& publicId,
213 const std::string& modality,
214 const std::string& date,
215 const std::string& patientId,
216 const std::string& studyInstanceUid,
217 const std::string& seriesInstanceUid,
218 const std::string& sopInstanceUid)
219 {
220 if (allowedAnswers_ != AllowedAnswers_All &&
221 allowedAnswers_ != AllowedAnswers_ExportedResource)
222 {
223 throw std::runtime_error("Cannot answer with an exported resource in the current state");
224 }
225
226 OrthancPluginExportedResource exported;
227 exported.seq = seq;
228 exported.resourceType = resourceType;
229 exported.publicId = publicId.c_str();
230 exported.modality = modality.c_str();
231 exported.date = date.c_str();
232 exported.patientId = patientId.c_str();
233 exported.studyInstanceUid = studyInstanceUid.c_str();
234 exported.seriesInstanceUid = seriesInstanceUid.c_str();
235 exported.sopInstanceUid = sopInstanceUid.c_str();
236
237 OrthancPluginDatabaseAnswerExportedResource(context_, database_, &exported);
238 }
239 };
240
241
242
243 class IDatabaseBackend : public NonCopyable
244 {
245 friend class DatabaseBackendAdapter;
246
247 private:
248 DatabaseBackendOutput* output_;
249
250 void Finalize()
251 {
252 if (output_ != NULL)
253 {
254 delete output_;
255 output_ = NULL;
256 }
257 }
258
259 protected:
260 DatabaseBackendOutput& GetOutput()
261 {
262 return *output_;
263 }
264
265 public:
266 IDatabaseBackend() : output_(NULL)
267 {
268 }
269
270 virtual ~IDatabaseBackend()
271 {
272 Finalize();
273 }
274
275 // This takes the ownership
276 void RegisterOutput(DatabaseBackendOutput* output)
277 {
278 Finalize();
279 output_ = output;
280 }
281
282 virtual void Open() = 0;
283
284 virtual void Close() = 0;
285
286 virtual void AddAttachment(int64_t id,
287 const OrthancPluginAttachment& attachment) = 0;
288
289 virtual void AttachChild(int64_t parent,
290 int64_t child) = 0;
291
292 virtual void ClearChanges() = 0;
293
294 virtual void ClearExportedResources() = 0;
295
296 virtual int64_t CreateResource(const char* publicId,
297 OrthancPluginResourceType type) = 0;
298
299 virtual void DeleteAttachment(int64_t id,
300 int32_t attachment) = 0;
301
302 virtual void DeleteMetadata(int64_t id,
303 int32_t metadataType) = 0;
304
305 virtual void DeleteResource(int64_t id) = 0;
306
307 virtual void GetAllPublicIds(std::list<std::string>& target,
308 OrthancPluginResourceType resourceType) = 0;
309
310 /* Use GetOutput().AnswerChange() */
311 virtual void GetChanges(bool& done /*out*/,
312 int64_t since,
313 uint32_t maxResults) = 0;
314
315 virtual void GetChildrenInternalId(std::list<int64_t>& target /*out*/,
316 int64_t id) = 0;
317
318 virtual void GetChildrenPublicId(std::list<std::string>& target /*out*/,
319 int64_t id) = 0;
320
321 /* Use GetOutput().AnswerExportedResource() */
322 virtual void GetExportedResources(bool& done /*out*/,
323 int64_t since,
324 uint32_t maxResults) = 0;
325
326 /* Use GetOutput().AnswerChange() */
327 virtual void GetLastChange() = 0;
328
329 /* Use GetOutput().AnswerExportedResource() */
330 virtual void GetLastExportedResource() = 0;
331
332 /* Use GetOutput().AnswerDicomTag() */
333 virtual void GetMainDicomTags(int64_t id) = 0;
334
335 virtual std::string GetPublicId(int64_t resourceId) = 0;
336
337 virtual uint64_t GetResourceCount(OrthancPluginResourceType resourceType) = 0;
338
339 virtual OrthancPluginResourceType GetResourceType(int64_t resourceId) = 0;
340
341 virtual uint64_t GetTotalCompressedSize() = 0;
342
343 virtual uint64_t GetTotalUncompressedSize() = 0;
344
345 virtual bool IsExistingResource(int64_t internalId) = 0;
346
347 virtual bool IsProtectedPatient(int64_t internalId) = 0;
348
349 virtual void ListAvailableMetadata(std::list<int32_t>& target /*out*/,
350 int64_t id) = 0;
351
352 virtual void ListAvailableAttachments(std::list<int32_t>& target /*out*/,
353 int64_t id) = 0;
354
355 virtual void LogChange(const OrthancPluginChange& change) = 0;
356
357 virtual void LogExportedResource(const OrthancPluginExportedResource& resource) = 0;
358
359 /* Use GetOutput().AnswerAttachment() */
360 virtual bool LookupAttachment(int64_t id,
361 int32_t contentType) = 0;
362
363 virtual bool LookupGlobalProperty(std::string& target /*out*/,
364 int32_t property) = 0;
365
366 /**
367 * "Identifiers" are necessarily one of the following tags:
368 * PatientID (0x0010, 0x0020), StudyInstanceUID (0x0020, 0x000d),
369 * SeriesInstanceUID (0x0020, 0x000e), SOPInstanceUID (0x0008,
370 * 0x0018) or AccessionNumber (0x0008, 0x0050).
371 **/
372 virtual void LookupIdentifier(std::list<int64_t>& target /*out*/,
373 uint16_t group,
374 uint16_t element,
375 const char* value) = 0;
376
377 virtual void LookupIdentifier(std::list<int64_t>& target /*out*/,
378 const char* value) = 0;
379
380 virtual bool LookupMetadata(std::string& target /*out*/,
381 int64_t id,
382 int32_t metadataType) = 0;
383
384 virtual bool LookupParent(int64_t& parentId /*out*/,
385 int64_t resourceId) = 0;
386
387 virtual bool LookupResource(int64_t& id /*out*/,
388 OrthancPluginResourceType& type /*out*/,
389 const char* publicId) = 0;
390
391 virtual bool SelectPatientToRecycle(int64_t& internalId /*out*/) = 0;
392
393 virtual bool SelectPatientToRecycle(int64_t& internalId /*out*/,
394 int64_t patientIdToAvoid) = 0;
395
396 virtual void SetGlobalProperty(int32_t property,
397 const char* value) = 0;
398
399 virtual void SetMainDicomTag(int64_t id,
400 uint16_t group,
401 uint16_t element,
402 const char* value) = 0;
403
404 virtual void SetIdentifierTag(int64_t id,
405 uint16_t group,
406 uint16_t element,
407 const char* value) = 0;
408
409 virtual void SetMetadata(int64_t id,
410 int32_t metadataType,
411 const char* value) = 0;
412
413 virtual void SetProtectedPatient(int64_t internalId,
414 bool isProtected) = 0;
415
416 virtual void StartTransaction() = 0;
417
418 virtual void RollbackTransaction() = 0;
419
420 virtual void CommitTransaction() = 0;
421 };
422
423
424
425 class DatabaseBackendAdapter
426 {
427 private:
428 // This class cannot be instantiated
429 DatabaseBackendAdapter()
430 {
431 }
432
433 static void LogError(IDatabaseBackend* backend,
434 const std::runtime_error& e)
435 {
436 backend->GetOutput().LogError("Exception in database back-end: " + std::string(e.what()));
437 }
438
439
440 static int32_t AddAttachment(void* payload,
441 int64_t id,
442 const OrthancPluginAttachment* attachment)
443 {
444 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
445 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
446
447 try
448 {
449 backend->AddAttachment(id, *attachment);
450 return 0;
451 }
452 catch (std::runtime_error& e)
453 {
454 LogError(backend, e);
455 return -1;
456 }
457 }
458
459
460 static int32_t AttachChild(void* payload,
461 int64_t parent,
462 int64_t child)
463 {
464 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
465 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
466
467 try
468 {
469 backend->AttachChild(parent, child);
470 return 0;
471 }
472 catch (std::runtime_error& e)
473 {
474 LogError(backend, e);
475 return -1;
476 }
477 }
478
479
480 static int32_t ClearChanges(void* payload)
481 {
482 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
483 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
484
485 try
486 {
487 backend->ClearChanges();
488 return 0;
489 }
490 catch (std::runtime_error& e)
491 {
492 LogError(backend, e);
493 return -1;
494 }
495 }
496
497
498 static int32_t ClearExportedResources(void* payload)
499 {
500 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
501 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
502
503 try
504 {
505 backend->ClearExportedResources();
506 return 0;
507 }
508 catch (std::runtime_error& e)
509 {
510 LogError(backend, e);
511 return -1;
512 }
513 }
514
515
516 static int32_t CreateResource(int64_t* id,
517 void* payload,
518 const char* publicId,
519 OrthancPluginResourceType resourceType)
520 {
521 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
522 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
523
524 try
525 {
526 *id = backend->CreateResource(publicId, resourceType);
527 return 0;
528 }
529 catch (std::runtime_error& e)
530 {
531 LogError(backend, e);
532 return -1;
533 }
534 }
535
536
537 static int32_t DeleteAttachment(void* payload,
538 int64_t id,
539 int32_t contentType)
540 {
541 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
542 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
543
544 try
545 {
546 backend->DeleteAttachment(id, contentType);
547 return 0;
548 }
549 catch (std::runtime_error& e)
550 {
551 LogError(backend, e);
552 return -1;
553 }
554 }
555
556
557 static int32_t DeleteMetadata(void* payload,
558 int64_t id,
559 int32_t metadataType)
560 {
561 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
562 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
563
564 try
565 {
566 backend->DeleteMetadata(id, metadataType);
567 return 0;
568 }
569 catch (std::runtime_error& e)
570 {
571 LogError(backend, e);
572 return -1;
573 }
574 }
575
576
577 static int32_t DeleteResource(void* payload,
578 int64_t id)
579 {
580 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
581 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
582
583 try
584 {
585 backend->DeleteResource(id);
586 return 0;
587 }
588 catch (std::runtime_error& e)
589 {
590 LogError(backend, e);
591 return -1;
592 }
593 }
594
595
596 static int32_t GetAllPublicIds(OrthancPluginDatabaseContext* context,
597 void* payload,
598 OrthancPluginResourceType resourceType)
599 {
600 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
601 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
602
603 try
604 {
605 std::list<std::string> ids;
606 backend->GetAllPublicIds(ids, resourceType);
607
608 for (std::list<std::string>::const_iterator
609 it = ids.begin(); it != ids.end(); ++it)
610 {
611 OrthancPluginDatabaseAnswerString(backend->GetOutput().context_,
612 backend->GetOutput().database_,
613 it->c_str());
614 }
615
616 return 0;
617 }
618 catch (std::runtime_error& e)
619 {
620 LogError(backend, e);
621 return -1;
622 }
623 }
624
625
626 static int32_t GetChanges(OrthancPluginDatabaseContext* context,
627 void* payload,
628 int64_t since,
629 uint32_t maxResult)
630 {
631 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
632 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_Change);
633
634 try
635 {
636 bool done;
637 backend->GetChanges(done, since, maxResult);
638
639 if (done)
640 {
641 OrthancPluginDatabaseAnswerChangesDone(backend->GetOutput().context_,
642 backend->GetOutput().database_);
643 }
644
645 return 0;
646 }
647 catch (std::runtime_error& e)
648 {
649 LogError(backend, e);
650 return -1;
651 }
652 }
653
654
655 static int32_t GetChildrenInternalId(OrthancPluginDatabaseContext* context,
656 void* payload,
657 int64_t id)
658 {
659 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
660 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
661
662 try
663 {
664 std::list<int64_t> target;
665 backend->GetChildrenInternalId(target, id);
666
667 for (std::list<int64_t>::const_iterator
668 it = target.begin(); it != target.end(); ++it)
669 {
670 OrthancPluginDatabaseAnswerInt64(backend->GetOutput().context_,
671 backend->GetOutput().database_, *it);
672 }
673
674 return 0;
675 }
676 catch (std::runtime_error& e)
677 {
678 LogError(backend, e);
679 return -1;
680 }
681 }
682
683
684 static int32_t GetChildrenPublicId(OrthancPluginDatabaseContext* context,
685 void* payload,
686 int64_t id)
687 {
688 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
689 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
690
691 try
692 {
693 std::list<std::string> ids;
694 backend->GetChildrenPublicId(ids, id);
695
696 for (std::list<std::string>::const_iterator
697 it = ids.begin(); it != ids.end(); ++it)
698 {
699 OrthancPluginDatabaseAnswerString(backend->GetOutput().context_,
700 backend->GetOutput().database_,
701 it->c_str());
702 }
703
704 return 0;
705 }
706 catch (std::runtime_error& e)
707 {
708 LogError(backend, e);
709 return -1;
710 }
711 }
712
713
714 static int32_t GetExportedResources(OrthancPluginDatabaseContext* context,
715 void* payload,
716 int64_t since,
717 uint32_t maxResult)
718 {
719 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
720 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_ExportedResource);
721
722 try
723 {
724 bool done;
725 backend->GetExportedResources(done, since, maxResult);
726
727 if (done)
728 {
729 OrthancPluginDatabaseAnswerExportedResourcesDone(backend->GetOutput().context_,
730 backend->GetOutput().database_);
731 }
732 return 0;
733 }
734 catch (std::runtime_error& e)
735 {
736 LogError(backend, e);
737 return -1;
738 }
739 }
740
741
742 static int32_t GetLastChange(OrthancPluginDatabaseContext* context,
743 void* payload)
744 {
745 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
746 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_Change);
747
748 try
749 {
750 backend->GetLastChange();
751 return 0;
752 }
753 catch (std::runtime_error& e)
754 {
755 LogError(backend, e);
756 return -1;
757 }
758 }
759
760
761 static int32_t GetLastExportedResource(OrthancPluginDatabaseContext* context,
762 void* payload)
763 {
764 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
765 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_ExportedResource);
766
767 try
768 {
769 backend->GetLastExportedResource();
770 return 0;
771 }
772 catch (std::runtime_error& e)
773 {
774 LogError(backend, e);
775 return -1;
776 }
777 }
778
779
780 static int32_t GetMainDicomTags(OrthancPluginDatabaseContext* context,
781 void* payload,
782 int64_t id)
783 {
784 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
785 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_DicomTag);
786
787 try
788 {
789 backend->GetMainDicomTags(id);
790 return 0;
791 }
792 catch (std::runtime_error& e)
793 {
794 LogError(backend, e);
795 return -1;
796 }
797 }
798
799
800 static int32_t GetPublicId(OrthancPluginDatabaseContext* context,
801 void* payload,
802 int64_t id)
803 {
804 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
805 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
806
807 try
808 {
809 std::string s = backend->GetPublicId(id);
810 OrthancPluginDatabaseAnswerString(backend->GetOutput().context_,
811 backend->GetOutput().database_,
812 s.c_str());
813
814 return 0;
815 }
816 catch (std::runtime_error& e)
817 {
818 LogError(backend, e);
819 return -1;
820 }
821 }
822
823
824 static int32_t GetResourceCount(uint64_t* target,
825 void* payload,
826 OrthancPluginResourceType resourceType)
827 {
828 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
829 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
830
831 try
832 {
833 *target = backend->GetResourceCount(resourceType);
834 return 0;
835 }
836 catch (std::runtime_error& e)
837 {
838 LogError(backend, e);
839 return -1;
840 }
841 }
842
843
844 static int32_t GetResourceType(OrthancPluginResourceType* resourceType,
845 void* payload,
846 int64_t id)
847 {
848 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
849 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
850
851 try
852 {
853 *resourceType = backend->GetResourceType(id);
854 return 0;
855 }
856 catch (std::runtime_error& e)
857 {
858 LogError(backend, e);
859 return -1;
860 }
861 }
862
863
864 static int32_t GetTotalCompressedSize(uint64_t* target,
865 void* payload)
866 {
867 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
868 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
869
870 try
871 {
872 *target = backend->GetTotalCompressedSize();
873 return 0;
874 }
875 catch (std::runtime_error& e)
876 {
877 LogError(backend, e);
878 return -1;
879 }
880 }
881
882
883 static int32_t GetTotalUncompressedSize(uint64_t* target,
884 void* payload)
885 {
886 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
887 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
888
889 try
890 {
891 *target = backend->GetTotalUncompressedSize();
892 return 0;
893 }
894 catch (std::runtime_error& e)
895 {
896 LogError(backend, e);
897 return -1;
898 }
899 }
900
901
902 static int32_t IsExistingResource(int32_t* existing,
903 void* payload,
904 int64_t id)
905 {
906 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
907 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
908
909 try
910 {
911 *existing = backend->IsExistingResource(id);
912 return 0;
913 }
914 catch (std::runtime_error& e)
915 {
916 LogError(backend, e);
917 return -1;
918 }
919 }
920
921
922 static int32_t IsProtectedPatient(int32_t* isProtected,
923 void* payload,
924 int64_t id)
925 {
926 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
927 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
928
929 try
930 {
931 *isProtected = backend->IsProtectedPatient(id);
932 return 0;
933 }
934 catch (std::runtime_error& e)
935 {
936 LogError(backend, e);
937 return -1;
938 }
939 }
940
941
942 static int32_t ListAvailableMetadata(OrthancPluginDatabaseContext* context,
943 void* payload,
944 int64_t id)
945 {
946 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
947 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
948
949 try
950 {
951 std::list<int32_t> target;
952 backend->ListAvailableMetadata(target, id);
953
954 for (std::list<int32_t>::const_iterator
955 it = target.begin(); it != target.end(); ++it)
956 {
957 OrthancPluginDatabaseAnswerInt32(backend->GetOutput().context_,
958 backend->GetOutput().database_,
959 *it);
960 }
961
962 return 0;
963 }
964 catch (std::runtime_error& e)
965 {
966 LogError(backend, e);
967 return -1;
968 }
969 }
970
971
972 static int32_t ListAvailableAttachments(OrthancPluginDatabaseContext* context,
973 void* payload,
974 int64_t id)
975 {
976 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
977 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
978
979 try
980 {
981 std::list<int32_t> target;
982 backend->ListAvailableAttachments(target, id);
983
984 for (std::list<int32_t>::const_iterator
985 it = target.begin(); it != target.end(); ++it)
986 {
987 OrthancPluginDatabaseAnswerInt32(backend->GetOutput().context_,
988 backend->GetOutput().database_,
989 *it);
990 }
991
992 return 0;
993 }
994 catch (std::runtime_error& e)
995 {
996 LogError(backend, e);
997 return -1;
998 }
999 }
1000
1001
1002 static int32_t LogChange(void* payload,
1003 const OrthancPluginChange* change)
1004 {
1005 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
1006 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
1007
1008 try
1009 {
1010 backend->LogChange(*change);
1011 return 0;
1012 }
1013 catch (std::runtime_error& e)
1014 {
1015 LogError(backend, e);
1016 return -1;
1017 }
1018 }
1019
1020
1021 static int32_t LogExportedResource(void* payload,
1022 const OrthancPluginExportedResource* exported)
1023 {
1024 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
1025 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
1026
1027 try
1028 {
1029 backend->LogExportedResource(*exported);
1030 return 0;
1031 }
1032 catch (std::runtime_error& e)
1033 {
1034 LogError(backend, e);
1035 return -1;
1036 }
1037 }
1038
1039
1040 static int32_t LookupAttachment(OrthancPluginDatabaseContext* context,
1041 void* payload,
1042 int64_t id,
1043 int32_t contentType)
1044 {
1045 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
1046 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_Attachment);
1047
1048 try
1049 {
1050 backend->LookupAttachment(id, contentType);
1051 return 0;
1052 }
1053 catch (std::runtime_error& e)
1054 {
1055 LogError(backend, e);
1056 return -1;
1057 }
1058 }
1059
1060
1061 static int32_t LookupGlobalProperty(OrthancPluginDatabaseContext* context,
1062 void* payload,
1063 int32_t property)
1064 {
1065 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
1066 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
1067
1068 try
1069 {
1070 std::string s;
1071 if (backend->LookupGlobalProperty(s, property))
1072 {
1073 OrthancPluginDatabaseAnswerString(backend->GetOutput().context_,
1074 backend->GetOutput().database_,
1075 s.c_str());
1076 }
1077
1078 return 0;
1079 }
1080 catch (std::runtime_error& e)
1081 {
1082 LogError(backend, e);
1083 return -1;
1084 }
1085 }
1086
1087
1088 static int32_t LookupIdentifier(OrthancPluginDatabaseContext* context,
1089 void* payload,
1090 const OrthancPluginDicomTag* tag)
1091 {
1092 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
1093 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
1094
1095 try
1096 {
1097 std::list<int64_t> target;
1098 backend->LookupIdentifier(target, tag->group, tag->element, tag->value);
1099
1100 for (std::list<int64_t>::const_iterator
1101 it = target.begin(); it != target.end(); ++it)
1102 {
1103 OrthancPluginDatabaseAnswerInt64(backend->GetOutput().context_,
1104 backend->GetOutput().database_, *it);
1105 }
1106
1107 return 0;
1108 }
1109 catch (std::runtime_error& e)
1110 {
1111 LogError(backend, e);
1112 return -1;
1113 }
1114 }
1115
1116
1117 static int32_t LookupIdentifier2(OrthancPluginDatabaseContext* context,
1118 void* payload,
1119 const char* value)
1120 {
1121 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
1122 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
1123
1124 try
1125 {
1126 std::list<int64_t> target;
1127 backend->LookupIdentifier(target, value);
1128
1129 for (std::list<int64_t>::const_iterator
1130 it = target.begin(); it != target.end(); ++it)
1131 {
1132 OrthancPluginDatabaseAnswerInt64(backend->GetOutput().context_,
1133 backend->GetOutput().database_, *it);
1134 }
1135
1136 return 0;
1137 }
1138 catch (std::runtime_error& e)
1139 {
1140 LogError(backend, e);
1141 return -1;
1142 }
1143 }
1144
1145
1146 static int32_t LookupMetadata(OrthancPluginDatabaseContext* context,
1147 void* payload,
1148 int64_t id,
1149 int32_t metadata)
1150 {
1151 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
1152 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
1153
1154 try
1155 {
1156 std::string s;
1157 if (backend->LookupMetadata(s, id, metadata))
1158 {
1159 OrthancPluginDatabaseAnswerString(backend->GetOutput().context_,
1160 backend->GetOutput().database_, s.c_str());
1161 }
1162
1163 return 0;
1164 }
1165 catch (std::runtime_error& e)
1166 {
1167 LogError(backend, e);
1168 return -1;
1169 }
1170 }
1171
1172
1173 static int32_t LookupParent(OrthancPluginDatabaseContext* context,
1174 void* payload,
1175 int64_t id)
1176 {
1177 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
1178 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
1179
1180 try
1181 {
1182 int64_t parent;
1183 if (backend->LookupParent(parent, id))
1184 {
1185 OrthancPluginDatabaseAnswerInt64(backend->GetOutput().context_,
1186 backend->GetOutput().database_, parent);
1187 }
1188
1189 return 0;
1190 }
1191 catch (std::runtime_error& e)
1192 {
1193 LogError(backend, e);
1194 return -1;
1195 }
1196 }
1197
1198
1199 static int32_t LookupResource(OrthancPluginDatabaseContext* context,
1200 void* payload,
1201 const char* publicId)
1202 {
1203 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
1204 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
1205
1206 try
1207 {
1208 int64_t id;
1209 OrthancPluginResourceType type;
1210 if (backend->LookupResource(id, type, publicId))
1211 {
1212 OrthancPluginDatabaseAnswerResource(backend->GetOutput().context_,
1213 backend->GetOutput().database_,
1214 id, type);
1215 }
1216
1217 return 0;
1218 }
1219 catch (std::runtime_error& e)
1220 {
1221 LogError(backend, e);
1222 return -1;
1223 }
1224 }
1225
1226
1227 static int32_t SelectPatientToRecycle(OrthancPluginDatabaseContext* context,
1228 void* payload)
1229 {
1230 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
1231 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
1232
1233 try
1234 {
1235 int64_t id;
1236 if (backend->SelectPatientToRecycle(id))
1237 {
1238 OrthancPluginDatabaseAnswerInt64(backend->GetOutput().context_,
1239 backend->GetOutput().database_, id);
1240 }
1241
1242 return 0;
1243 }
1244 catch (std::runtime_error& e)
1245 {
1246 LogError(backend, e);
1247 return -1;
1248 }
1249 }
1250
1251
1252 static int32_t SelectPatientToRecycle2(OrthancPluginDatabaseContext* context,
1253 void* payload,
1254 int64_t patientIdToAvoid)
1255 {
1256 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
1257 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
1258
1259 try
1260 {
1261 int64_t id;
1262 if (backend->SelectPatientToRecycle(id, patientIdToAvoid))
1263 {
1264 OrthancPluginDatabaseAnswerInt64(backend->GetOutput().context_,
1265 backend->GetOutput().database_, id);
1266 }
1267
1268 return 0;
1269 }
1270 catch (std::runtime_error& e)
1271 {
1272 LogError(backend, e);
1273 return -1;
1274 }
1275 }
1276
1277
1278 static int32_t SetGlobalProperty(void* payload,
1279 int32_t property,
1280 const char* value)
1281 {
1282 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
1283 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
1284
1285 try
1286 {
1287 backend->SetGlobalProperty(property, value);
1288 return 0;
1289 }
1290 catch (std::runtime_error& e)
1291 {
1292 LogError(backend, e);
1293 return -1;
1294 }
1295 }
1296
1297
1298 static int32_t SetMainDicomTag(void* payload,
1299 int64_t id,
1300 const OrthancPluginDicomTag* tag)
1301 {
1302 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
1303 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
1304
1305 try
1306 {
1307 backend->SetMainDicomTag(id, tag->group, tag->element, tag->value);
1308 return 0;
1309 }
1310 catch (std::runtime_error& e)
1311 {
1312 LogError(backend, e);
1313 return -1;
1314 }
1315 }
1316
1317
1318 static int32_t SetIdentifierTag(void* payload,
1319 int64_t id,
1320 const OrthancPluginDicomTag* tag)
1321 {
1322 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
1323 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
1324
1325 try
1326 {
1327 backend->SetIdentifierTag(id, tag->group, tag->element, tag->value);
1328 return 0;
1329 }
1330 catch (std::runtime_error& e)
1331 {
1332 LogError(backend, e);
1333 return -1;
1334 }
1335 }
1336
1337
1338 static int32_t SetMetadata(void* payload,
1339 int64_t id,
1340 int32_t metadata,
1341 const char* value)
1342 {
1343 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
1344 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
1345
1346 try
1347 {
1348 backend->SetMetadata(id, metadata, value);
1349 return 0;
1350 }
1351 catch (std::runtime_error& e)
1352 {
1353 LogError(backend, e);
1354 return -1;
1355 }
1356 }
1357
1358
1359 static int32_t SetProtectedPatient(void* payload,
1360 int64_t id,
1361 int32_t isProtected)
1362 {
1363 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
1364 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
1365
1366 try
1367 {
1368 backend->SetProtectedPatient(id, isProtected);
1369 return 0;
1370 }
1371 catch (std::runtime_error& e)
1372 {
1373 LogError(backend, e);
1374 return -1;
1375 }
1376 }
1377
1378
1379 static int32_t StartTransaction(void* payload)
1380 {
1381 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
1382 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
1383
1384 try
1385 {
1386 backend->StartTransaction();
1387 return 0;
1388 }
1389 catch (std::runtime_error& e)
1390 {
1391 LogError(backend, e);
1392 return -1;
1393 }
1394 }
1395
1396
1397 static int32_t RollbackTransaction(void* payload)
1398 {
1399 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
1400 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
1401
1402 try
1403 {
1404 backend->RollbackTransaction();
1405 return 0;
1406 }
1407 catch (std::runtime_error& e)
1408 {
1409 LogError(backend, e);
1410 return -1;
1411 }
1412 }
1413
1414
1415 static int32_t CommitTransaction(void* payload)
1416 {
1417 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
1418 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
1419
1420 try
1421 {
1422 backend->CommitTransaction();
1423 return 0;
1424 }
1425 catch (std::runtime_error& e)
1426 {
1427 LogError(backend, e);
1428 return -1;
1429 }
1430 }
1431
1432
1433 static int32_t Open(void* payload)
1434 {
1435 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
1436 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
1437
1438 try
1439 {
1440 backend->Open();
1441 return 0;
1442 }
1443 catch (std::runtime_error& e)
1444 {
1445 LogError(backend, e);
1446 return -1;
1447 }
1448 }
1449
1450
1451 static int32_t Close(void* payload)
1452 {
1453 IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
1454 backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None);
1455
1456 try
1457 {
1458 backend->Close();
1459 return 0;
1460 }
1461 catch (std::runtime_error& e)
1462 {
1463 LogError(backend, e);
1464 return -1;
1465 }
1466 }
1467
1468
1469 public:
1470 static void Register(OrthancPluginContext* context,
1471 IDatabaseBackend& backend)
1472 {
1473 OrthancPluginDatabaseBackend params;
1474 memset(&params, 0, sizeof(params));
1475
1476 params.addAttachment = AddAttachment;
1477 params.attachChild = AttachChild;
1478 params.clearChanges = ClearChanges;
1479 params.clearExportedResources = ClearExportedResources;
1480 params.createResource = CreateResource;
1481 params.deleteAttachment = DeleteAttachment;
1482 params.deleteMetadata = DeleteMetadata;
1483 params.deleteResource = DeleteResource;
1484 params.getAllPublicIds = GetAllPublicIds;
1485 params.getChanges = GetChanges;
1486 params.getChildrenInternalId = GetChildrenInternalId;
1487 params.getChildrenPublicId = GetChildrenPublicId;
1488 params.getExportedResources = GetExportedResources;
1489 params.getLastChange = GetLastChange;
1490 params.getLastExportedResource = GetLastExportedResource;
1491 params.getMainDicomTags = GetMainDicomTags;
1492 params.getPublicId = GetPublicId;
1493 params.getResourceCount = GetResourceCount;
1494 params.getResourceType = GetResourceType;
1495 params.getTotalCompressedSize = GetTotalCompressedSize;
1496 params.getTotalUncompressedSize = GetTotalUncompressedSize;
1497 params.isExistingResource = IsExistingResource;
1498 params.isProtectedPatient = IsProtectedPatient;
1499 params.listAvailableMetadata = ListAvailableMetadata;
1500 params.listAvailableAttachments = ListAvailableAttachments;
1501 params.logChange = LogChange;
1502 params.logExportedResource = LogExportedResource;
1503 params.lookupAttachment = LookupAttachment;
1504 params.lookupGlobalProperty = LookupGlobalProperty;
1505 params.lookupIdentifier = LookupIdentifier;
1506 params.lookupIdentifier2 = LookupIdentifier2;
1507 params.lookupMetadata = LookupMetadata;
1508 params.lookupParent = LookupParent;
1509 params.lookupResource = LookupResource;
1510 params.selectPatientToRecycle = SelectPatientToRecycle;
1511 params.selectPatientToRecycle2 = SelectPatientToRecycle2;
1512 params.setGlobalProperty = SetGlobalProperty;
1513 params.setMainDicomTag = SetMainDicomTag;
1514 params.setIdentifierTag = SetIdentifierTag;
1515 params.setMetadata = SetMetadata;
1516 params.setProtectedPatient = SetProtectedPatient;
1517 params.startTransaction = StartTransaction;
1518 params.rollbackTransaction = RollbackTransaction;
1519 params.commitTransaction = CommitTransaction;
1520 params.open = Open;
1521 params.close = Close;
1522
1523 OrthancPluginDatabaseContext* database = OrthancPluginRegisterDatabaseBackend(context, &params, &backend);
1524 if (!context)
1525 {
1526 throw std::runtime_error("Unable to register the database backend");
1527 }
1528
1529 backend.RegisterOutput(new DatabaseBackendOutput(context, database));
1530 }
1531 };
1532 }