comparison OrthancServer/Plugins/Engine/OrthancPluginDatabaseV3.cpp @ 4595:cc64385593ef db-changes

added OrthancPluginRegisterDatabaseBackendV3() to plugin sdk
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 16 Mar 2021 17:58:16 +0100
parents
children da2e0a457eae
comparison
equal deleted inserted replaced
4594:d494b4f1103e 4595:cc64385593ef
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-2021 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 "../../Sources/PrecompiledHeadersServer.h"
35 #include "OrthancPluginDatabaseV3.h"
36
37 #if ORTHANC_ENABLE_PLUGINS != 1
38 # error The plugin support is disabled
39 #endif
40
41 #include "../../../OrthancFramework/Sources/Logging.h"
42 #include "../../../OrthancFramework/Sources/OrthancException.h"
43 #include "../../Sources/Database/VoidDatabaseListener.h"
44 #include "PluginsEnumerations.h"
45
46 #include <cassert>
47
48 namespace Orthanc
49 {
50 class OrthancPluginDatabaseV3::Transaction : public IDatabaseWrapper::ITransaction
51 {
52 private:
53 OrthancPluginDatabaseV3& that_;
54 IDatabaseListener& listener_;
55 OrthancPluginDatabaseTransaction* transaction_;
56
57
58 void CheckSuccess(OrthancPluginErrorCode code) const
59 {
60 that_.CheckSuccess(code);
61 }
62
63
64 void ReadStringAnswers(std::list<std::string>& target)
65 {
66 uint32_t count;
67 CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
68
69 target.clear();
70 for (uint32_t i = 0; i < count; i++)
71 {
72 const char* value = NULL;
73 CheckSuccess(that_.backend_.readAnswerString(transaction_, &value, i));
74 if (value == NULL)
75 {
76 throw OrthancException(ErrorCode_DatabasePlugin);
77 }
78 else
79 {
80 target.push_back(value);
81 }
82 }
83 }
84
85
86 std::string ReadOneStringAnswer()
87 {
88 uint32_t count;
89 CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
90
91 if (count == 0)
92 {
93 throw OrthancException(ErrorCode_InexistentItem);
94 }
95 else if (count == 1)
96 {
97 const char* value = NULL;
98 CheckSuccess(that_.backend_.readAnswerString(transaction_, &value, 0));
99 if (value == NULL)
100 {
101 throw OrthancException(ErrorCode_DatabasePlugin);
102 }
103 else
104 {
105 return value;
106 }
107 }
108 else
109 {
110 throw OrthancException(ErrorCode_DatabasePlugin);
111 }
112 }
113
114
115 ExportedResource ReadAnswerExportedResource(uint32_t answerIndex)
116 {
117 OrthancPluginExportedResource exported;
118 CheckSuccess(that_.backend_.readAnswerExportedResource(transaction_, &exported, answerIndex));
119
120 if (exported.publicId == NULL ||
121 exported.modality == NULL ||
122 exported.date == NULL ||
123 exported.patientId == NULL ||
124 exported.studyInstanceUid == NULL ||
125 exported.seriesInstanceUid == NULL ||
126 exported.sopInstanceUid == NULL)
127 {
128 throw OrthancException(ErrorCode_DatabasePlugin);
129 }
130 else
131 {
132 return ExportedResource(exported.seq,
133 Plugins::Convert(exported.resourceType),
134 exported.publicId,
135 exported.modality,
136 exported.date,
137 exported.patientId,
138 exported.studyInstanceUid,
139 exported.seriesInstanceUid,
140 exported.sopInstanceUid);
141 }
142 }
143
144
145 ServerIndexChange ReadAnswerChange(uint32_t answerIndex)
146 {
147 OrthancPluginChange change;
148 CheckSuccess(that_.backend_.readAnswerChange(transaction_, &change, answerIndex));
149
150 if (change.publicId == NULL ||
151 change.date == NULL)
152 {
153 throw OrthancException(ErrorCode_DatabasePlugin);
154 }
155 else
156 {
157 return ServerIndexChange(change.seq,
158 static_cast<ChangeType>(change.changeType),
159 Plugins::Convert(change.resourceType),
160 change.publicId,
161 change.date);
162 }
163 }
164
165
166 public:
167 Transaction(OrthancPluginDatabaseV3& that,
168 IDatabaseListener& listener,
169 _OrthancPluginDatabaseTransactionType type) :
170 that_(that),
171 listener_(listener)
172 {
173 CheckSuccess(that.backend_.startTransaction(that.database_, &transaction_, type));
174 if (transaction_ == NULL)
175 {
176 throw OrthancException(ErrorCode_DatabasePlugin);
177 }
178 }
179
180
181 virtual ~Transaction()
182 {
183 OrthancPluginErrorCode code = that_.backend_.destructTransaction(transaction_);
184 if (code != OrthancPluginErrorCode_Success)
185 {
186 // Don't throw exception in destructors
187 that_.errorDictionary_.LogError(code, true);
188 }
189 }
190
191
192 virtual void Rollback() ORTHANC_OVERRIDE
193 {
194 CheckSuccess(that_.backend_.rollback(transaction_));
195 }
196
197
198 virtual void Commit(int64_t fileSizeDelta) ORTHANC_OVERRIDE
199 {
200 CheckSuccess(that_.backend_.commit(transaction_, fileSizeDelta));
201 }
202
203
204 virtual void AddAttachment(int64_t id,
205 const FileInfo& attachment) ORTHANC_OVERRIDE
206 {
207 OrthancPluginAttachment tmp;
208 tmp.uuid = attachment.GetUuid().c_str();
209 tmp.contentType = static_cast<int32_t>(attachment.GetContentType());
210 tmp.uncompressedSize = attachment.GetUncompressedSize();
211 tmp.uncompressedHash = attachment.GetUncompressedMD5().c_str();
212 tmp.compressionType = static_cast<int32_t>(attachment.GetCompressionType());
213 tmp.compressedSize = attachment.GetCompressedSize();
214 tmp.compressedHash = attachment.GetCompressedMD5().c_str();
215
216 CheckSuccess(that_.backend_.addAttachment(transaction_, id, &tmp));
217 }
218
219
220 virtual void ClearChanges() ORTHANC_OVERRIDE
221 {
222 CheckSuccess(that_.backend_.clearChanges(transaction_));
223 }
224
225
226 virtual void ClearExportedResources() ORTHANC_OVERRIDE
227 {
228 CheckSuccess(that_.backend_.clearExportedResources(transaction_));
229 }
230
231
232 virtual void DeleteAttachment(int64_t id,
233 FileContentType attachment) ORTHANC_OVERRIDE
234 {
235 CheckSuccess(that_.backend_.deleteAttachment(transaction_, id, static_cast<int32_t>(attachment)));
236 }
237
238
239 virtual void DeleteMetadata(int64_t id,
240 MetadataType type) ORTHANC_OVERRIDE
241 {
242 CheckSuccess(that_.backend_.deleteMetadata(transaction_, id, static_cast<int32_t>(type)));
243 }
244
245
246 virtual void DeleteResource(int64_t id) ORTHANC_OVERRIDE
247 {
248 CheckSuccess(that_.backend_.deleteResource(transaction_, id));
249 }
250
251
252 virtual void GetAllMetadata(std::map<MetadataType, std::string>& target,
253 int64_t id) ORTHANC_OVERRIDE
254 {
255 CheckSuccess(that_.backend_.getAllMetadata(transaction_, id));
256
257 uint32_t count;
258 CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
259
260 target.clear();
261 for (uint32_t i = 0; i < count; i++)
262 {
263 int32_t metadata;
264 const char* value = NULL;
265 CheckSuccess(that_.backend_.readAnswerMetadata(transaction_, &metadata, &value, i));
266
267 if (value == NULL)
268 {
269 throw OrthancException(ErrorCode_DatabasePlugin);
270 }
271 else
272 {
273 target[static_cast<MetadataType>(metadata)] = value;
274 }
275 }
276 }
277
278
279 virtual void GetAllPublicIds(std::list<std::string>& target,
280 ResourceType resourceType) ORTHANC_OVERRIDE
281 {
282 CheckSuccess(that_.backend_.getAllPublicIds(transaction_, Plugins::Convert(resourceType)));
283 ReadStringAnswers(target);
284 }
285
286
287 virtual void GetAllPublicIds(std::list<std::string>& target,
288 ResourceType resourceType,
289 size_t since,
290 size_t limit) ORTHANC_OVERRIDE
291 {
292 CheckSuccess(that_.backend_.getAllPublicIdsWithLimit(
293 transaction_, Plugins::Convert(resourceType),
294 static_cast<uint64_t>(since), static_cast<uint64_t>(limit)));
295 ReadStringAnswers(target);
296 }
297
298
299 virtual void GetChanges(std::list<ServerIndexChange>& target /*out*/,
300 bool& done /*out*/,
301 int64_t since,
302 uint32_t maxResults) ORTHANC_OVERRIDE
303 {
304 uint8_t tmpDone = true;
305 CheckSuccess(that_.backend_.getChanges(transaction_, &tmpDone, since, maxResults));
306
307 done = (tmpDone != 0);
308
309 uint32_t count;
310 CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
311
312 target.clear();
313 for (uint32_t i = 0; i < count; i++)
314 {
315 target.push_back(ReadAnswerChange(i));
316 }
317 }
318
319
320 virtual void GetChildrenInternalId(std::list<int64_t>& target,
321 int64_t id) ORTHANC_OVERRIDE
322 {
323 CheckSuccess(that_.backend_.getChildrenInternalId(transaction_, id));
324
325 uint32_t count;
326 CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
327
328 target.clear();
329 for (uint32_t i = 0; i < count; i++)
330 {
331 int64_t value;
332 CheckSuccess(that_.backend_.readAnswerInt64(transaction_, &value, i));
333 target.push_back(value);
334 }
335 }
336
337
338 virtual void GetChildrenPublicId(std::list<std::string>& target,
339 int64_t id) ORTHANC_OVERRIDE
340 {
341 CheckSuccess(that_.backend_.getChildrenPublicId(transaction_, id));
342 ReadStringAnswers(target);
343 }
344
345
346 virtual void GetExportedResources(std::list<ExportedResource>& target /*out*/,
347 bool& done /*out*/,
348 int64_t since,
349 uint32_t maxResults) ORTHANC_OVERRIDE
350 {
351 uint8_t tmpDone = true;
352 CheckSuccess(that_.backend_.getExportedResources(transaction_, &tmpDone, since, maxResults));
353
354 done = (tmpDone != 0);
355
356 uint32_t count;
357 CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
358
359 target.clear();
360 for (uint32_t i = 0; i < count; i++)
361 {
362 target.push_back(ReadAnswerExportedResource(i));
363 }
364 }
365
366
367 virtual void GetLastChange(std::list<ServerIndexChange>& target /*out*/) ORTHANC_OVERRIDE
368 {
369 CheckSuccess(that_.backend_.getLastChange(transaction_));
370
371 uint32_t count;
372 CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
373
374 target.clear();
375 if (count == 1)
376 {
377 target.push_back(ReadAnswerChange(0));
378 }
379 else if (count > 1)
380 {
381 throw OrthancException(ErrorCode_DatabasePlugin);
382 }
383 }
384
385
386 virtual void GetLastExportedResource(std::list<ExportedResource>& target /*out*/) ORTHANC_OVERRIDE
387 {
388 CheckSuccess(that_.backend_.getLastExportedResource(transaction_));
389
390 uint32_t count;
391 CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
392
393 target.clear();
394 if (count == 1)
395 {
396 target.push_back(ReadAnswerExportedResource(0));
397 }
398 else if (count > 1)
399 {
400 throw OrthancException(ErrorCode_DatabasePlugin);
401 }
402 }
403
404
405 virtual void GetMainDicomTags(DicomMap& target,
406 int64_t id) ORTHANC_OVERRIDE
407 {
408 CheckSuccess(that_.backend_.getMainDicomTags(transaction_, id));
409
410 uint32_t count;
411 CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
412
413 target.Clear();
414 for (uint32_t i = 0; i < count; i++)
415 {
416 uint16_t group, element;
417 const char* value = NULL;
418 CheckSuccess(that_.backend_.readAnswerDicomTag(transaction_, &group, &element, &value, i));
419
420 if (value == NULL)
421 {
422 throw OrthancException(ErrorCode_DatabasePlugin);
423 }
424 else
425 {
426 target.SetValue(group, element, std::string(value), false);
427 }
428 }
429 }
430
431
432 virtual std::string GetPublicId(int64_t resourceId) ORTHANC_OVERRIDE
433 {
434 CheckSuccess(that_.backend_.getPublicId(transaction_, resourceId));
435 return ReadOneStringAnswer();
436 }
437
438
439 virtual uint64_t GetResourcesCount(ResourceType resourceType) ORTHANC_OVERRIDE
440 {
441 uint64_t value;
442 CheckSuccess(that_.backend_.getResourcesCount(transaction_, &value, Plugins::Convert(resourceType)));
443 return value;
444 }
445
446
447 virtual ResourceType GetResourceType(int64_t resourceId) ORTHANC_OVERRIDE
448 {
449 OrthancPluginResourceType type;
450 CheckSuccess(that_.backend_.getResourceType(transaction_, &type, resourceId));
451 return Plugins::Convert(type);
452 }
453
454
455 virtual uint64_t GetTotalCompressedSize() ORTHANC_OVERRIDE
456 {
457 uint64_t s;
458 CheckSuccess(that_.backend_.getTotalCompressedSize(transaction_, &s));
459 return s;
460 }
461
462
463 virtual uint64_t GetTotalUncompressedSize() ORTHANC_OVERRIDE
464 {
465 uint64_t s;
466 CheckSuccess(that_.backend_.getTotalUncompressedSize(transaction_, &s));
467 return s;
468 }
469
470
471 virtual bool IsExistingResource(int64_t internalId) ORTHANC_OVERRIDE
472 {
473 uint8_t b;
474 CheckSuccess(that_.backend_.isExistingResource(transaction_, &b, internalId));
475 return (b != 0);
476 }
477
478
479 virtual bool IsProtectedPatient(int64_t internalId) ORTHANC_OVERRIDE
480 {
481 uint8_t b;
482 CheckSuccess(that_.backend_.isProtectedPatient(transaction_, &b, internalId));
483 return (b != 0);
484 }
485
486
487 virtual void ListAvailableAttachments(std::set<FileContentType>& target,
488 int64_t id) ORTHANC_OVERRIDE
489 {
490 CheckSuccess(that_.backend_.listAvailableAttachments(transaction_, id));
491
492 uint32_t count;
493 CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
494
495 target.clear();
496 for (uint32_t i = 0; i < count; i++)
497 {
498 int32_t value;
499 CheckSuccess(that_.backend_.readAnswerInt32(transaction_, &value, i));
500 target.insert(static_cast<FileContentType>(value));
501 }
502 }
503
504
505 virtual void LogChange(int64_t internalId,
506 const ServerIndexChange& change) ORTHANC_OVERRIDE
507 {
508 CheckSuccess(that_.backend_.logChange(transaction_, static_cast<int32_t>(change.GetChangeType()),
509 internalId, Plugins::Convert(change.GetResourceType()),
510 change.GetPublicId().c_str(), change.GetDate().c_str()));
511 }
512
513
514 virtual void LogExportedResource(const ExportedResource& resource) ORTHANC_OVERRIDE
515 {
516 }
517
518
519 virtual bool LookupAttachment(FileInfo& attachment,
520 int64_t id,
521 FileContentType contentType) ORTHANC_OVERRIDE
522 {
523 }
524
525
526 virtual bool LookupGlobalProperty(std::string& target,
527 GlobalProperty property) ORTHANC_OVERRIDE
528 {
529 }
530
531
532 virtual bool LookupMetadata(std::string& target,
533 int64_t id,
534 MetadataType type) ORTHANC_OVERRIDE
535 {
536 }
537
538
539 virtual bool LookupParent(int64_t& parentId,
540 int64_t resourceId) ORTHANC_OVERRIDE
541 {
542 }
543
544
545 virtual bool LookupResource(int64_t& id,
546 ResourceType& type,
547 const std::string& publicId) ORTHANC_OVERRIDE
548 {
549 }
550
551
552 virtual bool SelectPatientToRecycle(int64_t& internalId) ORTHANC_OVERRIDE
553 {
554 }
555
556
557 virtual bool SelectPatientToRecycle(int64_t& internalId,
558 int64_t patientIdToAvoid) ORTHANC_OVERRIDE
559 {
560 }
561
562
563 virtual void SetGlobalProperty(GlobalProperty property,
564 const std::string& value) ORTHANC_OVERRIDE
565 {
566 }
567
568
569 virtual void ClearMainDicomTags(int64_t id) ORTHANC_OVERRIDE
570 {
571 }
572
573
574 virtual void SetMetadata(int64_t id,
575 MetadataType type,
576 const std::string& value) ORTHANC_OVERRIDE
577 {
578 }
579
580
581 virtual void SetProtectedPatient(int64_t internalId,
582 bool isProtected) ORTHANC_OVERRIDE
583 {
584 }
585
586
587 virtual bool IsDiskSizeAbove(uint64_t threshold) ORTHANC_OVERRIDE
588 {
589 }
590
591
592 virtual void ApplyLookupResources(std::list<std::string>& resourcesId,
593 std::list<std::string>* instancesId, // Can be NULL if not needed
594 const std::vector<DatabaseConstraint>& lookup,
595 ResourceType queryLevel,
596 size_t limit) ORTHANC_OVERRIDE
597 {
598 }
599
600
601 virtual bool CreateInstance(CreateInstanceResult& result, /* out */
602 int64_t& instanceId, /* out */
603 const std::string& patient,
604 const std::string& study,
605 const std::string& series,
606 const std::string& instance) ORTHANC_OVERRIDE
607 {
608 }
609
610
611 virtual void SetResourcesContent(const ResourcesContent& content) ORTHANC_OVERRIDE
612 {
613 }
614
615
616 virtual void GetChildrenMetadata(std::list<std::string>& target,
617 int64_t resourceId,
618 MetadataType metadata) ORTHANC_OVERRIDE
619 {
620 }
621
622
623 virtual int64_t GetLastChangeIndex() ORTHANC_OVERRIDE
624 {
625
626 }
627
628
629 virtual bool LookupResourceAndParent(int64_t& id,
630 ResourceType& type,
631 std::string& parentPublicId,
632 const std::string& publicId) ORTHANC_OVERRIDE
633 {
634 }
635 };
636
637
638 void OrthancPluginDatabaseV3::CheckSuccess(OrthancPluginErrorCode code)
639 {
640 if (code != OrthancPluginErrorCode_Success)
641 {
642 errorDictionary_.LogError(code, true);
643 throw OrthancException(static_cast<ErrorCode>(code));
644 }
645 }
646
647
648 OrthancPluginDatabaseV3::OrthancPluginDatabaseV3(SharedLibrary& library,
649 PluginsErrorDictionary& errorDictionary,
650 const OrthancPluginDatabaseBackendV3* backend,
651 size_t backendSize,
652 OrthancPluginDatabaseContext* database) :
653 library_(library),
654 errorDictionary_(errorDictionary),
655 database_(database)
656 {
657 if (backendSize >= sizeof(backend_))
658 {
659 memcpy(&backend_, backend, sizeof(backend_));
660 }
661 else
662 {
663 // Not all the primitives are implemented by the plugin
664 memset(&backend_, 0, sizeof(backend_));
665 memcpy(&backend_, backend, backendSize);
666 }
667 }
668
669
670 OrthancPluginDatabaseV3::~OrthancPluginDatabaseV3()
671 {
672 if (database_ != NULL)
673 {
674 OrthancPluginErrorCode code = backend_.destructDatabase(database_);
675 if (code != OrthancPluginErrorCode_Success)
676 {
677 // Don't throw exception in destructors
678 errorDictionary_.LogError(code, true);
679 }
680 }
681 }
682
683
684 void OrthancPluginDatabaseV3::Open()
685 {
686 CheckSuccess(backend_.open(database_));
687 }
688
689
690 void OrthancPluginDatabaseV3::Close()
691 {
692 CheckSuccess(backend_.close(database_));
693 }
694
695
696 IDatabaseWrapper::ITransaction* OrthancPluginDatabaseV3::StartTransaction(TransactionType type,
697 IDatabaseListener& listener)
698 {
699 switch (type)
700 {
701 case TransactionType_ReadOnly:
702 return new Transaction(*this, listener, _OrthancPluginDatabaseTransactionType_ReadOnly);
703
704 case TransactionType_ReadWrite:
705 return new Transaction(*this, listener, _OrthancPluginDatabaseTransactionType_ReadWrite);
706
707 default:
708 throw OrthancException(ErrorCode_InternalError);
709 }
710 }
711
712
713 unsigned int OrthancPluginDatabaseV3::GetDatabaseVersion()
714 {
715 uint32_t version = 0;
716 CheckSuccess(backend_.getDatabaseVersion(database_, &version));
717 return version;
718 }
719
720
721 void OrthancPluginDatabaseV3::Upgrade(unsigned int targetVersion,
722 IStorageArea& storageArea)
723 {
724 VoidDatabaseListener listener;
725
726 if (backend_.upgradeDatabase != NULL)
727 {
728 Transaction transaction(*this, listener, _OrthancPluginDatabaseTransactionType_ReadWrite);
729
730 OrthancPluginErrorCode code = backend_.upgradeDatabase(
731 database_, reinterpret_cast<OrthancPluginStorageArea*>(&storageArea),
732 static_cast<uint32_t>(targetVersion));
733
734 if (code == OrthancPluginErrorCode_Success)
735 {
736 transaction.Commit(0);
737 }
738 else
739 {
740 transaction.Rollback();
741 errorDictionary_.LogError(code, true);
742 throw OrthancException(static_cast<ErrorCode>(code));
743 }
744 }
745 }
746 }