comparison OrthancServer/Plugins/Engine/OrthancPluginDatabase.cpp @ 4591:ff8170d17d90 db-changes

moving all accesses to databases from IDatabaseWrapper to ITransaction
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 15 Mar 2021 15:30:42 +0100
parents bec74e29f86b
children 36bbf3169a27
comparison
equal deleted inserted replaced
4590:4a0bf1019335 4591:ff8170d17d90
39 #endif 39 #endif
40 40
41 41
42 #include "../../../OrthancFramework/Sources/Logging.h" 42 #include "../../../OrthancFramework/Sources/Logging.h"
43 #include "../../../OrthancFramework/Sources/OrthancException.h" 43 #include "../../../OrthancFramework/Sources/OrthancException.h"
44 #include "../../Sources/Database/VoidDatabaseListener.h"
44 #include "PluginsEnumerations.h" 45 #include "PluginsEnumerations.h"
45 46
46 #include <cassert> 47 #include <cassert>
47 48
48 namespace Orthanc 49 namespace Orthanc
49 { 50 {
50 class OrthancPluginDatabase::Transaction : public IDatabaseWrapper::ITransaction 51 class OrthancPluginDatabase::Transaction :
52 public IDatabaseWrapper::ITransaction,
53 public Compatibility::ICreateInstance,
54 public Compatibility::IGetChildrenMetadata,
55 public Compatibility::ILookupResources,
56 public Compatibility::ILookupResourceAndParent,
57 public Compatibility::ISetResourcesContent
51 { 58 {
52 private: 59 private:
53 OrthancPluginDatabase& that_; 60 OrthancPluginDatabase& that_;
54 61
55 void CheckSuccess(OrthancPluginErrorCode code) const 62 void CheckSuccess(OrthancPluginErrorCode code) const
99 throw OrthancException(ErrorCode_DatabasePlugin); 106 throw OrthancException(ErrorCode_DatabasePlugin);
100 } 107 }
101 108
102 uint64_t newDiskSize = (that_.currentDiskSize_ + diskSizeDelta); 109 uint64_t newDiskSize = (that_.currentDiskSize_ + diskSizeDelta);
103 110
104 assert(newDiskSize == that_.GetTotalCompressedSize()); 111 assert(newDiskSize == GetTotalCompressedSize());
105 112
106 CheckSuccess(that_.backend_.commitTransaction(that_.payload_)); 113 CheckSuccess(that_.backend_.commitTransaction(that_.payload_));
107 114
108 // The transaction has succeeded, we can commit the new disk size 115 // The transaction has succeeded, we can commit the new disk size
109 that_.currentDiskSize_ = newDiskSize; 116 that_.currentDiskSize_ = newDiskSize;
110 } 117 }
111 } 118 }
119
120
121 // From the "ILookupResources" interface
122 void GetAllInternalIds(std::list<int64_t>& target,
123 ResourceType resourceType) ORTHANC_OVERRIDE
124 {
125 if (that_.extensions_.getAllInternalIds == NULL)
126 {
127 throw OrthancException(ErrorCode_DatabasePlugin,
128 "The database plugin does not implement the mandatory GetAllInternalIds() extension");
129 }
130
131 that_.ResetAnswers();
132 CheckSuccess(that_.extensions_.getAllInternalIds(that_.GetContext(), that_.payload_, Plugins::Convert(resourceType)));
133 that_.ForwardAnswers(target);
134 }
135
136
137
138 // From the "ILookupResources" interface
139 void LookupIdentifier(std::list<int64_t>& result,
140 ResourceType level,
141 const DicomTag& tag,
142 Compatibility::IdentifierConstraintType type,
143 const std::string& value) ORTHANC_OVERRIDE
144 {
145 if (that_.extensions_.lookupIdentifier3 == NULL)
146 {
147 throw OrthancException(ErrorCode_DatabasePlugin,
148 "The database plugin does not implement the mandatory LookupIdentifier3() extension");
149 }
150
151 OrthancPluginDicomTag tmp;
152 tmp.group = tag.GetGroup();
153 tmp.element = tag.GetElement();
154 tmp.value = value.c_str();
155
156 that_.ResetAnswers();
157 CheckSuccess(that_.extensions_.lookupIdentifier3(that_.GetContext(), that_.payload_, Plugins::Convert(level),
158 &tmp, Compatibility::Convert(type)));
159 that_.ForwardAnswers(result);
160 }
161
162
163
164 /**
165 * Implementation of "ITransaction"
166 **/
167
168 virtual void ApplyLookupResources(std::list<std::string>& resourcesId,
169 std::list<std::string>* instancesId,
170 const std::vector<DatabaseConstraint>& lookup,
171 ResourceType queryLevel,
172 size_t limit) ORTHANC_OVERRIDE
173 {
174 if (that_.extensions_.lookupResources == NULL)
175 {
176 // Fallback to compatibility mode
177 ILookupResources::Apply
178 (*this, *this, resourcesId, instancesId, lookup, queryLevel, limit);
179 }
180 else
181 {
182 std::vector<OrthancPluginDatabaseConstraint> constraints;
183 std::vector< std::vector<const char*> > constraintsValues;
184
185 constraints.resize(lookup.size());
186 constraintsValues.resize(lookup.size());
187
188 for (size_t i = 0; i < lookup.size(); i++)
189 {
190 lookup[i].EncodeForPlugins(constraints[i], constraintsValues[i]);
191 }
192
193 that_.ResetAnswers();
194 that_.answerMatchingResources_ = &resourcesId;
195 that_.answerMatchingInstances_ = instancesId;
196
197 CheckSuccess(that_.extensions_.lookupResources(that_.GetContext(), that_.payload_, lookup.size(),
198 (lookup.empty() ? NULL : &constraints[0]),
199 Plugins::Convert(queryLevel),
200 limit, (instancesId == NULL ? 0 : 1)));
201 }
202 }
203
204
205 bool CreateInstance(IDatabaseWrapper::CreateInstanceResult& result,
206 int64_t& instanceId,
207 const std::string& patient,
208 const std::string& study,
209 const std::string& series,
210 const std::string& instance) ORTHANC_OVERRIDE
211 {
212 if (that_.extensions_.createInstance == NULL)
213 {
214 // Fallback to compatibility mode
215 return ICreateInstance::Apply
216 (*this, result, instanceId, patient, study, series, instance);
217 }
218 else
219 {
220 OrthancPluginCreateInstanceResult output;
221 memset(&output, 0, sizeof(output));
222
223 CheckSuccess(that_.extensions_.createInstance(&output, that_.payload_, patient.c_str(),
224 study.c_str(), series.c_str(), instance.c_str()));
225
226 instanceId = output.instanceId;
227
228 if (output.isNewInstance)
229 {
230 result.isNewPatient_ = output.isNewPatient;
231 result.isNewStudy_ = output.isNewStudy;
232 result.isNewSeries_ = output.isNewSeries;
233 result.patientId_ = output.patientId;
234 result.studyId_ = output.studyId;
235 result.seriesId_ = output.seriesId;
236 return true;
237 }
238 else
239 {
240 return false;
241 }
242 }
243 }
244
245
246 virtual int64_t CreateResource(const std::string& publicId,
247 ResourceType type) ORTHANC_OVERRIDE
248 {
249 int64_t id;
250 CheckSuccess(that_.backend_.createResource(&id, that_.payload_, publicId.c_str(), Plugins::Convert(type)));
251 return id;
252 }
253
254
255 virtual void AddAttachment(int64_t id,
256 const FileInfo& attachment) ORTHANC_OVERRIDE
257 {
258 OrthancPluginAttachment tmp;
259 tmp.uuid = attachment.GetUuid().c_str();
260 tmp.contentType = static_cast<int32_t>(attachment.GetContentType());
261 tmp.uncompressedSize = attachment.GetUncompressedSize();
262 tmp.uncompressedHash = attachment.GetUncompressedMD5().c_str();
263 tmp.compressionType = static_cast<int32_t>(attachment.GetCompressionType());
264 tmp.compressedSize = attachment.GetCompressedSize();
265 tmp.compressedHash = attachment.GetCompressedMD5().c_str();
266
267 CheckSuccess(that_.backend_.addAttachment(that_.payload_, id, &tmp));
268 }
269
270
271 virtual void AttachChild(int64_t parent,
272 int64_t child) ORTHANC_OVERRIDE
273 {
274 CheckSuccess(that_.backend_.attachChild(that_.payload_, parent, child));
275 }
276
277
278 virtual void ClearChanges() ORTHANC_OVERRIDE
279 {
280 CheckSuccess(that_.backend_.clearChanges(that_.payload_));
281 }
282
283
284 virtual void ClearExportedResources() ORTHANC_OVERRIDE
285 {
286 CheckSuccess(that_.backend_.clearExportedResources(that_.payload_));
287 }
288
289
290 virtual void ClearMainDicomTags(int64_t id) ORTHANC_OVERRIDE
291 {
292 if (that_.extensions_.clearMainDicomTags == NULL)
293 {
294 throw OrthancException(ErrorCode_DatabasePlugin,
295 "Your custom index plugin does not implement the mandatory ClearMainDicomTags() extension");
296 }
297
298 CheckSuccess(that_.extensions_.clearMainDicomTags(that_.payload_, id));
299 }
300
301
302 virtual void DeleteAttachment(int64_t id,
303 FileContentType attachment) ORTHANC_OVERRIDE
304 {
305 CheckSuccess(that_.backend_.deleteAttachment(that_.payload_, id, static_cast<int32_t>(attachment)));
306 }
307
308
309 virtual void DeleteMetadata(int64_t id,
310 MetadataType type) ORTHANC_OVERRIDE
311 {
312 CheckSuccess(that_.backend_.deleteMetadata(that_.payload_, id, static_cast<int32_t>(type)));
313 }
314
315
316 virtual void DeleteResource(int64_t id) ORTHANC_OVERRIDE
317 {
318 CheckSuccess(that_.backend_.deleteResource(that_.payload_, id));
319 }
320
321
322 virtual void GetAllMetadata(std::map<MetadataType, std::string>& target,
323 int64_t id) ORTHANC_OVERRIDE
324 {
325 if (that_.extensions_.getAllMetadata == NULL)
326 {
327 // Fallback implementation if extension is missing
328 target.clear();
329
330 that_.ResetAnswers();
331 CheckSuccess(that_.backend_.listAvailableMetadata(that_.GetContext(), that_.payload_, id));
332
333 if (that_.type_ != _OrthancPluginDatabaseAnswerType_None &&
334 that_.type_ != _OrthancPluginDatabaseAnswerType_Int32)
335 {
336 throw OrthancException(ErrorCode_DatabasePlugin);
337 }
338
339 target.clear();
340
341 if (that_.type_ == _OrthancPluginDatabaseAnswerType_Int32)
342 {
343 for (std::list<int32_t>::const_iterator
344 it = that_.answerInt32_.begin(); it != that_.answerInt32_.end(); ++it)
345 {
346 MetadataType type = static_cast<MetadataType>(*it);
347
348 std::string value;
349 if (LookupMetadata(value, id, type))
350 {
351 target[type] = value;
352 }
353 }
354 }
355 }
356 else
357 {
358 that_.ResetAnswers();
359
360 that_.answerMetadata_ = &target;
361 target.clear();
362
363 CheckSuccess(that_.extensions_.getAllMetadata(that_.GetContext(), that_.payload_, id));
364
365 if (that_.type_ != _OrthancPluginDatabaseAnswerType_None &&
366 that_.type_ != _OrthancPluginDatabaseAnswerType_Metadata)
367 {
368 throw OrthancException(ErrorCode_DatabasePlugin);
369 }
370 }
371 }
372
373
374 virtual void GetAllPublicIds(std::list<std::string>& target,
375 ResourceType resourceType) ORTHANC_OVERRIDE
376 {
377 that_.ResetAnswers();
378 CheckSuccess(that_.backend_.getAllPublicIds(that_.GetContext(), that_.payload_, Plugins::Convert(resourceType)));
379 that_.ForwardAnswers(target);
380 }
381
382
383 virtual void GetAllPublicIds(std::list<std::string>& target,
384 ResourceType resourceType,
385 size_t since,
386 size_t limit) ORTHANC_OVERRIDE
387 {
388 if (that_.extensions_.getAllPublicIdsWithLimit != NULL)
389 {
390 // This extension is available since Orthanc 0.9.4
391 that_.ResetAnswers();
392 CheckSuccess(that_.extensions_.getAllPublicIdsWithLimit
393 (that_.GetContext(), that_.payload_, Plugins::Convert(resourceType), since, limit));
394 that_.ForwardAnswers(target);
395 }
396 else
397 {
398 // The extension is not available in the database plugin, use a
399 // fallback implementation
400 target.clear();
401
402 if (limit == 0)
403 {
404 return;
405 }
406
407 std::list<std::string> tmp;
408 GetAllPublicIds(tmp, resourceType);
409
410 if (tmp.size() <= since)
411 {
412 // Not enough results => empty answer
413 return;
414 }
415
416 std::list<std::string>::iterator current = tmp.begin();
417 std::advance(current, since);
418
419 while (limit > 0 && current != tmp.end())
420 {
421 target.push_back(*current);
422 --limit;
423 ++current;
424 }
425 }
426 }
427
428
429 virtual void GetChanges(std::list<ServerIndexChange>& target /*out*/,
430 bool& done /*out*/,
431 int64_t since,
432 uint32_t maxResults) ORTHANC_OVERRIDE
433 {
434 that_.ResetAnswers();
435 that_.answerChanges_ = &target;
436 that_.answerDone_ = &done;
437 done = false;
438
439 CheckSuccess(that_.backend_.getChanges(that_.GetContext(), that_.payload_, since, maxResults));
440 }
441
442
443 virtual void GetChildrenInternalId(std::list<int64_t>& target,
444 int64_t id) ORTHANC_OVERRIDE
445 {
446 that_.ResetAnswers();
447 CheckSuccess(that_.backend_.getChildrenInternalId(that_.GetContext(), that_.payload_, id));
448 that_.ForwardAnswers(target);
449 }
450
451
452 virtual void GetChildrenMetadata(std::list<std::string>& target,
453 int64_t resourceId,
454 MetadataType metadata) ORTHANC_OVERRIDE
455 {
456 if (that_.extensions_.getChildrenMetadata == NULL)
457 {
458 IGetChildrenMetadata::Apply(*this, target, resourceId, metadata);
459 }
460 else
461 {
462 that_.ResetAnswers();
463 CheckSuccess(that_.extensions_.getChildrenMetadata
464 (that_.GetContext(), that_.payload_, resourceId, static_cast<int32_t>(metadata)));
465 that_.ForwardAnswers(target);
466 }
467 }
468
469
470 virtual void GetChildrenPublicId(std::list<std::string>& target,
471 int64_t id) ORTHANC_OVERRIDE
472 {
473 that_.ResetAnswers();
474 CheckSuccess(that_.backend_.getChildrenPublicId(that_.GetContext(), that_.payload_, id));
475 that_.ForwardAnswers(target);
476 }
477
478
479 virtual void GetExportedResources(std::list<ExportedResource>& target /*out*/,
480 bool& done /*out*/,
481 int64_t since,
482 uint32_t maxResults) ORTHANC_OVERRIDE
483 {
484 that_.ResetAnswers();
485 that_.answerExportedResources_ = &target;
486 that_.answerDone_ = &done;
487 done = false;
488
489 CheckSuccess(that_.backend_.getExportedResources(that_.GetContext(), that_.payload_, since, maxResults));
490 }
491
492
493 virtual void GetLastChange(std::list<ServerIndexChange>& target /*out*/) ORTHANC_OVERRIDE
494 {
495 that_.answerDoneIgnored_ = false;
496
497 that_.ResetAnswers();
498 that_.answerChanges_ = &target;
499 that_.answerDone_ = &that_.answerDoneIgnored_;
500
501 CheckSuccess(that_.backend_.getLastChange(that_.GetContext(), that_.payload_));
502 }
503
504
505 int64_t GetLastChangeIndex() ORTHANC_OVERRIDE
506 {
507 if (that_.extensions_.getLastChangeIndex == NULL)
508 {
509 // This was the default behavior in Orthanc <= 1.5.1
510 // https://groups.google.com/d/msg/orthanc-users/QhzB6vxYeZ0/YxabgqpfBAAJ
511 return 0;
512 }
513 else
514 {
515 int64_t result = 0;
516 CheckSuccess(that_.extensions_.getLastChangeIndex(&result, that_.payload_));
517 return result;
518 }
519 }
520
521
522 virtual void GetLastExportedResource(std::list<ExportedResource>& target /*out*/) ORTHANC_OVERRIDE
523 {
524 that_.answerDoneIgnored_ = false;
525
526 that_.ResetAnswers();
527 that_.answerExportedResources_ = &target;
528 that_.answerDone_ = &that_.answerDoneIgnored_;
529
530 CheckSuccess(that_.backend_.getLastExportedResource(that_.GetContext(), that_.payload_));
531 }
532
533
534 virtual void GetMainDicomTags(DicomMap& map,
535 int64_t id) ORTHANC_OVERRIDE
536 {
537 that_.ResetAnswers();
538 that_.answerDicomMap_ = &map;
539
540 CheckSuccess(that_.backend_.getMainDicomTags(that_.GetContext(), that_.payload_, id));
541 }
542
543
544 virtual std::string GetPublicId(int64_t resourceId) ORTHANC_OVERRIDE
545 {
546 that_.ResetAnswers();
547 std::string s;
548
549 CheckSuccess(that_.backend_.getPublicId(that_.GetContext(), that_.payload_, resourceId));
550
551 if (!that_.ForwardSingleAnswer(s))
552 {
553 throw OrthancException(ErrorCode_DatabasePlugin);
554 }
555
556 return s;
557 }
558
559
560 virtual uint64_t GetResourceCount(ResourceType resourceType) ORTHANC_OVERRIDE
561 {
562 uint64_t count;
563 CheckSuccess(that_.backend_.getResourceCount(&count, that_.payload_, Plugins::Convert(resourceType)));
564 return count;
565 }
566
567
568 virtual ResourceType GetResourceType(int64_t resourceId) ORTHANC_OVERRIDE
569 {
570 OrthancPluginResourceType type;
571 CheckSuccess(that_.backend_.getResourceType(&type, that_.payload_, resourceId));
572 return Plugins::Convert(type);
573 }
574
575
576 virtual uint64_t GetTotalCompressedSize() ORTHANC_OVERRIDE
577 {
578 uint64_t size;
579 CheckSuccess(that_.backend_.getTotalCompressedSize(&size, that_.payload_));
580 return size;
581 }
582
583
584 virtual uint64_t GetTotalUncompressedSize() ORTHANC_OVERRIDE
585 {
586 uint64_t size;
587 CheckSuccess(that_.backend_.getTotalUncompressedSize(&size, that_.payload_));
588 return size;
589 }
590
591
592 virtual bool IsDiskSizeAbove(uint64_t threshold) ORTHANC_OVERRIDE
593 {
594 if (that_.fastGetTotalSize_)
595 {
596 return GetTotalCompressedSize() > threshold;
597 }
598 else
599 {
600 assert(GetTotalCompressedSize() == that_.currentDiskSize_);
601 return that_.currentDiskSize_ > threshold;
602 }
603 }
604
605
606 virtual bool IsExistingResource(int64_t internalId) ORTHANC_OVERRIDE
607 {
608 int32_t existing;
609 CheckSuccess(that_.backend_.isExistingResource(&existing, that_.payload_, internalId));
610 return (existing != 0);
611 }
612
613
614 virtual bool IsProtectedPatient(int64_t internalId) ORTHANC_OVERRIDE
615 {
616 int32_t isProtected;
617 CheckSuccess(that_.backend_.isProtectedPatient(&isProtected, that_.payload_, internalId));
618 return (isProtected != 0);
619 }
620
621
622 virtual void ListAvailableAttachments(std::set<FileContentType>& target,
623 int64_t id) ORTHANC_OVERRIDE
624 {
625 that_.ResetAnswers();
626
627 CheckSuccess(that_.backend_.listAvailableAttachments(that_.GetContext(), that_.payload_, id));
628
629 if (that_.type_ != _OrthancPluginDatabaseAnswerType_None &&
630 that_.type_ != _OrthancPluginDatabaseAnswerType_Int32)
631 {
632 throw OrthancException(ErrorCode_DatabasePlugin);
633 }
634
635 target.clear();
636
637 if (that_.type_ == _OrthancPluginDatabaseAnswerType_Int32)
638 {
639 for (std::list<int32_t>::const_iterator
640 it = that_.answerInt32_.begin(); it != that_.answerInt32_.end(); ++it)
641 {
642 target.insert(static_cast<FileContentType>(*it));
643 }
644 }
645 }
646
647
648 virtual void LogChange(int64_t internalId,
649 const ServerIndexChange& change) ORTHANC_OVERRIDE
650 {
651 OrthancPluginChange tmp;
652 tmp.seq = change.GetSeq();
653 tmp.changeType = static_cast<int32_t>(change.GetChangeType());
654 tmp.resourceType = Plugins::Convert(change.GetResourceType());
655 tmp.publicId = change.GetPublicId().c_str();
656 tmp.date = change.GetDate().c_str();
657
658 CheckSuccess(that_.backend_.logChange(that_.payload_, &tmp));
659 }
660
661
662 virtual void LogExportedResource(const ExportedResource& resource) ORTHANC_OVERRIDE
663 {
664 OrthancPluginExportedResource tmp;
665 tmp.seq = resource.GetSeq();
666 tmp.resourceType = Plugins::Convert(resource.GetResourceType());
667 tmp.publicId = resource.GetPublicId().c_str();
668 tmp.modality = resource.GetModality().c_str();
669 tmp.date = resource.GetDate().c_str();
670 tmp.patientId = resource.GetPatientId().c_str();
671 tmp.studyInstanceUid = resource.GetStudyInstanceUid().c_str();
672 tmp.seriesInstanceUid = resource.GetSeriesInstanceUid().c_str();
673 tmp.sopInstanceUid = resource.GetSopInstanceUid().c_str();
674
675 CheckSuccess(that_.backend_.logExportedResource(that_.payload_, &tmp));
676 }
677
678
679 virtual bool LookupAttachment(FileInfo& attachment,
680 int64_t id,
681 FileContentType contentType) ORTHANC_OVERRIDE
682 {
683 that_.ResetAnswers();
684
685 CheckSuccess(that_.backend_.lookupAttachment
686 (that_.GetContext(), that_.payload_, id, static_cast<int32_t>(contentType)));
687
688 if (that_.type_ == _OrthancPluginDatabaseAnswerType_None)
689 {
690 return false;
691 }
692 else if (that_.type_ == _OrthancPluginDatabaseAnswerType_Attachment &&
693 that_.answerAttachments_.size() == 1)
694 {
695 attachment = that_.answerAttachments_.front();
696 return true;
697 }
698 else
699 {
700 throw OrthancException(ErrorCode_DatabasePlugin);
701 }
702 }
703
704
705 virtual bool LookupGlobalProperty(std::string& target,
706 GlobalProperty property) ORTHANC_OVERRIDE
707 {
708 that_.ResetAnswers();
709
710 CheckSuccess(that_.backend_.lookupGlobalProperty
711 (that_.GetContext(), that_.payload_, static_cast<int32_t>(property)));
712
713 return that_.ForwardSingleAnswer(target);
714 }
715
716
717 virtual void LookupIdentifierRange(std::list<int64_t>& result,
718 ResourceType level,
719 const DicomTag& tag,
720 const std::string& start,
721 const std::string& end) ORTHANC_OVERRIDE
722 {
723 if (that_.extensions_.lookupIdentifierRange == NULL)
724 {
725 // Default implementation, for plugins using Orthanc SDK <= 1.3.2
726
727 LookupIdentifier(result, level, tag, Compatibility::IdentifierConstraintType_GreaterOrEqual, start);
728
729 std::list<int64_t> b;
730 LookupIdentifier(result, level, tag, Compatibility::IdentifierConstraintType_SmallerOrEqual, end);
731
732 result.splice(result.end(), b);
733 }
734 else
735 {
736 that_.ResetAnswers();
737 CheckSuccess(that_.extensions_.lookupIdentifierRange(that_.GetContext(), that_.payload_, Plugins::Convert(level),
738 tag.GetGroup(), tag.GetElement(),
739 start.c_str(), end.c_str()));
740 that_.ForwardAnswers(result);
741 }
742 }
743
744
745 virtual bool LookupMetadata(std::string& target,
746 int64_t id,
747 MetadataType type) ORTHANC_OVERRIDE
748 {
749 that_.ResetAnswers();
750 CheckSuccess(that_.backend_.lookupMetadata(that_.GetContext(), that_.payload_, id, static_cast<int32_t>(type)));
751 return that_.ForwardSingleAnswer(target);
752 }
753
754
755 virtual bool LookupParent(int64_t& parentId,
756 int64_t resourceId) ORTHANC_OVERRIDE
757 {
758 that_.ResetAnswers();
759 CheckSuccess(that_.backend_.lookupParent(that_.GetContext(), that_.payload_, resourceId));
760 return that_.ForwardSingleAnswer(parentId);
761 }
762
763
764 virtual bool LookupResource(int64_t& id,
765 ResourceType& type,
766 const std::string& publicId) ORTHANC_OVERRIDE
767 {
768 that_.ResetAnswers();
769
770 CheckSuccess(that_.backend_.lookupResource(that_.GetContext(), that_.payload_, publicId.c_str()));
771
772 if (that_.type_ == _OrthancPluginDatabaseAnswerType_None)
773 {
774 return false;
775 }
776 else if (that_.type_ == _OrthancPluginDatabaseAnswerType_Resource &&
777 that_.answerResources_.size() == 1)
778 {
779 id = that_.answerResources_.front().first;
780 type = that_.answerResources_.front().second;
781 return true;
782 }
783 else
784 {
785 throw OrthancException(ErrorCode_DatabasePlugin);
786 }
787 }
788
789
790 virtual bool LookupResourceAndParent(int64_t& id,
791 ResourceType& type,
792 std::string& parentPublicId,
793 const std::string& publicId) ORTHANC_OVERRIDE
794 {
795 if (that_.extensions_.lookupResourceAndParent == NULL)
796 {
797 return ILookupResourceAndParent::Apply(*this, id, type, parentPublicId, publicId);
798 }
799 else
800 {
801 std::list<std::string> parent;
802
803 uint8_t isExisting;
804 OrthancPluginResourceType pluginType = OrthancPluginResourceType_Patient;
805
806 that_.ResetAnswers();
807 CheckSuccess(that_.extensions_.lookupResourceAndParent
808 (that_.GetContext(), &isExisting, &id, &pluginType, that_.payload_, publicId.c_str()));
809 that_.ForwardAnswers(parent);
810
811 if (isExisting)
812 {
813 type = Plugins::Convert(pluginType);
814
815 if (parent.empty())
816 {
817 if (type != ResourceType_Patient)
818 {
819 throw OrthancException(ErrorCode_DatabasePlugin);
820 }
821 }
822 else if (parent.size() == 1)
823 {
824 if ((type != ResourceType_Study &&
825 type != ResourceType_Series &&
826 type != ResourceType_Instance) ||
827 parent.front().empty())
828 {
829 throw OrthancException(ErrorCode_DatabasePlugin);
830 }
831
832 parentPublicId = parent.front();
833 }
834 else
835 {
836 throw OrthancException(ErrorCode_DatabasePlugin);
837 }
838
839 return true;
840 }
841 else
842 {
843 return false;
844 }
845 }
846 }
847
848
849 virtual bool SelectPatientToRecycle(int64_t& internalId) ORTHANC_OVERRIDE
850 {
851 that_.ResetAnswers();
852 CheckSuccess(that_.backend_.selectPatientToRecycle(that_.GetContext(), that_.payload_));
853 return that_.ForwardSingleAnswer(internalId);
854 }
855
856
857 virtual bool SelectPatientToRecycle(int64_t& internalId,
858 int64_t patientIdToAvoid) ORTHANC_OVERRIDE
859 {
860 that_.ResetAnswers();
861 CheckSuccess(that_.backend_.selectPatientToRecycle2(that_.GetContext(), that_.payload_, patientIdToAvoid));
862 return that_.ForwardSingleAnswer(internalId);
863 }
864
865
866 virtual void SetGlobalProperty(GlobalProperty property,
867 const std::string& value) ORTHANC_OVERRIDE
868 {
869 CheckSuccess(that_.backend_.setGlobalProperty
870 (that_.payload_, static_cast<int32_t>(property), value.c_str()));
871 }
872
873
874 virtual void SetIdentifierTag(int64_t id,
875 const DicomTag& tag,
876 const std::string& value) ORTHANC_OVERRIDE
877 {
878 OrthancPluginDicomTag tmp;
879 tmp.group = tag.GetGroup();
880 tmp.element = tag.GetElement();
881 tmp.value = value.c_str();
882
883 CheckSuccess(that_.backend_.setIdentifierTag(that_.payload_, id, &tmp));
884 }
885
886
887 virtual void SetMainDicomTag(int64_t id,
888 const DicomTag& tag,
889 const std::string& value) ORTHANC_OVERRIDE
890 {
891 OrthancPluginDicomTag tmp;
892 tmp.group = tag.GetGroup();
893 tmp.element = tag.GetElement();
894 tmp.value = value.c_str();
895
896 CheckSuccess(that_.backend_.setMainDicomTag(that_.payload_, id, &tmp));
897 }
898
899
900 virtual void SetMetadata(int64_t id,
901 MetadataType type,
902 const std::string& value) ORTHANC_OVERRIDE
903 {
904 CheckSuccess(that_.backend_.setMetadata
905 (that_.payload_, id, static_cast<int32_t>(type), value.c_str()));
906 }
907
908
909 virtual void SetProtectedPatient(int64_t internalId,
910 bool isProtected) ORTHANC_OVERRIDE
911 {
912 CheckSuccess(that_.backend_.setProtectedPatient(that_.payload_, internalId, isProtected));
913 }
914
915
916 virtual void SetResourcesContent(const Orthanc::ResourcesContent& content) ORTHANC_OVERRIDE
917 {
918 if (that_.extensions_.setResourcesContent == NULL)
919 {
920 ISetResourcesContent::Apply(*this, content);
921 }
922 else
923 {
924 std::vector<OrthancPluginResourcesContentTags> identifierTags;
925 std::vector<OrthancPluginResourcesContentTags> mainDicomTags;
926 std::vector<OrthancPluginResourcesContentMetadata> metadata;
927
928 identifierTags.reserve(content.GetListTags().size());
929 mainDicomTags.reserve(content.GetListTags().size());
930 metadata.reserve(content.GetListMetadata().size());
931
932 for (ResourcesContent::ListTags::const_iterator
933 it = content.GetListTags().begin(); it != content.GetListTags().end(); ++it)
934 {
935 OrthancPluginResourcesContentTags tmp;
936 tmp.resource = it->resourceId_;
937 tmp.group = it->tag_.GetGroup();
938 tmp.element = it->tag_.GetElement();
939 tmp.value = it->value_.c_str();
940
941 if (it->isIdentifier_)
942 {
943 identifierTags.push_back(tmp);
944 }
945 else
946 {
947 mainDicomTags.push_back(tmp);
948 }
949 }
950
951 for (ResourcesContent::ListMetadata::const_iterator
952 it = content.GetListMetadata().begin(); it != content.GetListMetadata().end(); ++it)
953 {
954 OrthancPluginResourcesContentMetadata tmp;
955 tmp.resource = it->resourceId_;
956 tmp.metadata = it->metadata_;
957 tmp.value = it->value_.c_str();
958 metadata.push_back(tmp);
959 }
960
961 assert(identifierTags.size() + mainDicomTags.size() == content.GetListTags().size() &&
962 metadata.size() == content.GetListMetadata().size());
963
964 CheckSuccess(that_.extensions_.setResourcesContent(
965 that_.payload_,
966 identifierTags.size(),
967 (identifierTags.empty() ? NULL : &identifierTags[0]),
968 mainDicomTags.size(),
969 (mainDicomTags.empty() ? NULL : &mainDicomTags[0]),
970 metadata.size(),
971 (metadata.empty() ? NULL : &metadata[0])));
972 }
973 }
974
975
976 virtual void TagMostRecentPatient(int64_t patient) ORTHANC_OVERRIDE
977 {
978 if (that_.extensions_.tagMostRecentPatient != NULL)
979 {
980 CheckSuccess(that_.extensions_.tagMostRecentPatient(that_.payload_, patient));
981 }
982 }
983
112 }; 984 };
113 985
114 986
115 static FileInfo Convert(const OrthancPluginAttachment& attachment) 987 static FileInfo Convert(const OrthancPluginAttachment& attachment)
116 { 988 {
317 << "(affected by issue 58)"; 1189 << "(affected by issue 58)";
318 } 1190 }
319 } 1191 }
320 1192
321 1193
322 namespace
323 {
324 class VoidListener : public IDatabaseListener
325 {
326 public:
327 virtual void SignalRemainingAncestor(ResourceType parentType,
328 const std::string& publicId)
329 {
330 throw OrthancException(ErrorCode_InternalError); // Should be read-only transaction
331 }
332
333 virtual void SignalAttachmentDeleted(const FileInfo& info)
334 {
335 throw OrthancException(ErrorCode_InternalError); // Should be read-only transaction
336 }
337
338 virtual void SignalResourceDeleted(ResourceType type,
339 const std::string& publicId)
340 {
341 throw OrthancException(ErrorCode_InternalError); // Should be read-only transaction
342 }
343 };
344 }
345
346
347 void OrthancPluginDatabase::Open() 1194 void OrthancPluginDatabase::Open()
348 { 1195 {
349 CheckSuccess(backend_.open(payload_)); 1196 CheckSuccess(backend_.open(payload_));
350 1197
351 VoidListener listener; 1198 VoidDatabaseListener listener;
352 1199
353 { 1200 {
354 Transaction transaction(*this, listener); 1201 Transaction transaction(*this, listener);
355 transaction.Begin(); 1202 transaction.Begin();
356 1203
357 std::string tmp; 1204 std::string tmp;
358 fastGetTotalSize_ = 1205 fastGetTotalSize_ =
359 (LookupGlobalProperty(tmp, GlobalProperty_GetTotalSizeIsFast) && 1206 (transaction.LookupGlobalProperty(tmp, GlobalProperty_GetTotalSizeIsFast) &&
360 tmp == "1"); 1207 tmp == "1");
361 1208
362 if (fastGetTotalSize_) 1209 if (fastGetTotalSize_)
363 { 1210 {
364 currentDiskSize_ = 0; // Unused 1211 currentDiskSize_ = 0; // Unused
365 } 1212 }
366 else 1213 else
367 { 1214 {
368 // This is the case of database plugins using Orthanc SDK <= 1.5.2 1215 // This is the case of database plugins using Orthanc SDK <= 1.5.2
369 LOG(WARNING) << "Your database index plugin is not compatible with multiple Orthanc writers"; 1216 LOG(WARNING) << "Your database index plugin is not compatible with multiple Orthanc writers";
370 currentDiskSize_ = GetTotalCompressedSize(); 1217 currentDiskSize_ = transaction.GetTotalCompressedSize();
371 } 1218 }
372 1219
373 transaction.Commit(0); 1220 transaction.Commit(0);
374 } 1221 }
375 }
376
377
378 void OrthancPluginDatabase::AddAttachment(int64_t id,
379 const FileInfo& attachment)
380 {
381 OrthancPluginAttachment tmp;
382 tmp.uuid = attachment.GetUuid().c_str();
383 tmp.contentType = static_cast<int32_t>(attachment.GetContentType());
384 tmp.uncompressedSize = attachment.GetUncompressedSize();
385 tmp.uncompressedHash = attachment.GetUncompressedMD5().c_str();
386 tmp.compressionType = static_cast<int32_t>(attachment.GetCompressionType());
387 tmp.compressedSize = attachment.GetCompressedSize();
388 tmp.compressedHash = attachment.GetCompressedMD5().c_str();
389
390 CheckSuccess(backend_.addAttachment(payload_, id, &tmp));
391 }
392
393
394 void OrthancPluginDatabase::AttachChild(int64_t parent,
395 int64_t child)
396 {
397 CheckSuccess(backend_.attachChild(payload_, parent, child));
398 }
399
400
401 void OrthancPluginDatabase::ClearChanges()
402 {
403 CheckSuccess(backend_.clearChanges(payload_));
404 }
405
406
407 void OrthancPluginDatabase::ClearExportedResources()
408 {
409 CheckSuccess(backend_.clearExportedResources(payload_));
410 }
411
412
413 int64_t OrthancPluginDatabase::CreateResource(const std::string& publicId,
414 ResourceType type)
415 {
416 int64_t id;
417 CheckSuccess(backend_.createResource(&id, payload_, publicId.c_str(), Plugins::Convert(type)));
418 return id;
419 }
420
421
422 void OrthancPluginDatabase::DeleteAttachment(int64_t id,
423 FileContentType attachment)
424 {
425 CheckSuccess(backend_.deleteAttachment(payload_, id, static_cast<int32_t>(attachment)));
426 }
427
428
429 void OrthancPluginDatabase::DeleteMetadata(int64_t id,
430 MetadataType type)
431 {
432 CheckSuccess(backend_.deleteMetadata(payload_, id, static_cast<int32_t>(type)));
433 }
434
435
436 void OrthancPluginDatabase::DeleteResource(int64_t id)
437 {
438 CheckSuccess(backend_.deleteResource(payload_, id));
439 }
440
441
442 void OrthancPluginDatabase::GetAllMetadata(std::map<MetadataType, std::string>& target,
443 int64_t id)
444 {
445 if (extensions_.getAllMetadata == NULL)
446 {
447 // Fallback implementation if extension is missing
448 target.clear();
449
450 ResetAnswers();
451 CheckSuccess(backend_.listAvailableMetadata(GetContext(), payload_, id));
452
453 if (type_ != _OrthancPluginDatabaseAnswerType_None &&
454 type_ != _OrthancPluginDatabaseAnswerType_Int32)
455 {
456 throw OrthancException(ErrorCode_DatabasePlugin);
457 }
458
459 target.clear();
460
461 if (type_ == _OrthancPluginDatabaseAnswerType_Int32)
462 {
463 for (std::list<int32_t>::const_iterator
464 it = answerInt32_.begin(); it != answerInt32_.end(); ++it)
465 {
466 MetadataType type = static_cast<MetadataType>(*it);
467
468 std::string value;
469 if (LookupMetadata(value, id, type))
470 {
471 target[type] = value;
472 }
473 }
474 }
475 }
476 else
477 {
478 ResetAnswers();
479
480 answerMetadata_ = &target;
481 target.clear();
482
483 CheckSuccess(extensions_.getAllMetadata(GetContext(), payload_, id));
484
485 if (type_ != _OrthancPluginDatabaseAnswerType_None &&
486 type_ != _OrthancPluginDatabaseAnswerType_Metadata)
487 {
488 throw OrthancException(ErrorCode_DatabasePlugin);
489 }
490 }
491 }
492
493
494 void OrthancPluginDatabase::GetAllInternalIds(std::list<int64_t>& target,
495 ResourceType resourceType)
496 {
497 if (extensions_.getAllInternalIds == NULL)
498 {
499 throw OrthancException(ErrorCode_DatabasePlugin,
500 "The database plugin does not implement the mandatory GetAllInternalIds() extension");
501 }
502
503 ResetAnswers();
504 CheckSuccess(extensions_.getAllInternalIds(GetContext(), payload_, Plugins::Convert(resourceType)));
505 ForwardAnswers(target);
506 }
507
508
509 void OrthancPluginDatabase::GetAllPublicIds(std::list<std::string>& target,
510 ResourceType resourceType)
511 {
512 ResetAnswers();
513 CheckSuccess(backend_.getAllPublicIds(GetContext(), payload_, Plugins::Convert(resourceType)));
514 ForwardAnswers(target);
515 }
516
517
518 void OrthancPluginDatabase::GetAllPublicIds(std::list<std::string>& target,
519 ResourceType resourceType,
520 size_t since,
521 size_t limit)
522 {
523 if (extensions_.getAllPublicIdsWithLimit != NULL)
524 {
525 // This extension is available since Orthanc 0.9.4
526 ResetAnswers();
527 CheckSuccess(extensions_.getAllPublicIdsWithLimit
528 (GetContext(), payload_, Plugins::Convert(resourceType), since, limit));
529 ForwardAnswers(target);
530 }
531 else
532 {
533 // The extension is not available in the database plugin, use a
534 // fallback implementation
535 target.clear();
536
537 if (limit == 0)
538 {
539 return;
540 }
541
542 std::list<std::string> tmp;
543 GetAllPublicIds(tmp, resourceType);
544
545 if (tmp.size() <= since)
546 {
547 // Not enough results => empty answer
548 return;
549 }
550
551 std::list<std::string>::iterator current = tmp.begin();
552 std::advance(current, since);
553
554 while (limit > 0 && current != tmp.end())
555 {
556 target.push_back(*current);
557 --limit;
558 ++current;
559 }
560 }
561 }
562
563
564
565 void OrthancPluginDatabase::GetChanges(std::list<ServerIndexChange>& target /*out*/,
566 bool& done /*out*/,
567 int64_t since,
568 uint32_t maxResults)
569 {
570 ResetAnswers();
571 answerChanges_ = &target;
572 answerDone_ = &done;
573 done = false;
574
575 CheckSuccess(backend_.getChanges(GetContext(), payload_, since, maxResults));
576 }
577
578
579 void OrthancPluginDatabase::GetChildrenInternalId(std::list<int64_t>& target,
580 int64_t id)
581 {
582 ResetAnswers();
583 CheckSuccess(backend_.getChildrenInternalId(GetContext(), payload_, id));
584 ForwardAnswers(target);
585 }
586
587
588 void OrthancPluginDatabase::GetChildrenPublicId(std::list<std::string>& target,
589 int64_t id)
590 {
591 ResetAnswers();
592 CheckSuccess(backend_.getChildrenPublicId(GetContext(), payload_, id));
593 ForwardAnswers(target);
594 }
595
596
597 void OrthancPluginDatabase::GetExportedResources(std::list<ExportedResource>& target /*out*/,
598 bool& done /*out*/,
599 int64_t since,
600 uint32_t maxResults)
601 {
602 ResetAnswers();
603 answerExportedResources_ = &target;
604 answerDone_ = &done;
605 done = false;
606
607 CheckSuccess(backend_.getExportedResources(GetContext(), payload_, since, maxResults));
608 }
609
610
611 void OrthancPluginDatabase::GetLastChange(std::list<ServerIndexChange>& target /*out*/)
612 {
613 answerDoneIgnored_ = false;
614
615 ResetAnswers();
616 answerChanges_ = &target;
617 answerDone_ = &answerDoneIgnored_;
618
619 CheckSuccess(backend_.getLastChange(GetContext(), payload_));
620 }
621
622
623 void OrthancPluginDatabase::GetLastExportedResource(std::list<ExportedResource>& target /*out*/)
624 {
625 answerDoneIgnored_ = false;
626
627 ResetAnswers();
628 answerExportedResources_ = &target;
629 answerDone_ = &answerDoneIgnored_;
630
631 CheckSuccess(backend_.getLastExportedResource(GetContext(), payload_));
632 }
633
634
635 void OrthancPluginDatabase::GetMainDicomTags(DicomMap& map,
636 int64_t id)
637 {
638 ResetAnswers();
639 answerDicomMap_ = &map;
640
641 CheckSuccess(backend_.getMainDicomTags(GetContext(), payload_, id));
642 }
643
644
645 std::string OrthancPluginDatabase::GetPublicId(int64_t resourceId)
646 {
647 ResetAnswers();
648 std::string s;
649
650 CheckSuccess(backend_.getPublicId(GetContext(), payload_, resourceId));
651
652 if (!ForwardSingleAnswer(s))
653 {
654 throw OrthancException(ErrorCode_DatabasePlugin);
655 }
656
657 return s;
658 }
659
660
661 uint64_t OrthancPluginDatabase::GetResourceCount(ResourceType resourceType)
662 {
663 uint64_t count;
664 CheckSuccess(backend_.getResourceCount(&count, payload_, Plugins::Convert(resourceType)));
665 return count;
666 }
667
668
669 ResourceType OrthancPluginDatabase::GetResourceType(int64_t resourceId)
670 {
671 OrthancPluginResourceType type;
672 CheckSuccess(backend_.getResourceType(&type, payload_, resourceId));
673 return Plugins::Convert(type);
674 }
675
676
677 uint64_t OrthancPluginDatabase::GetTotalCompressedSize()
678 {
679 uint64_t size;
680 CheckSuccess(backend_.getTotalCompressedSize(&size, payload_));
681 return size;
682 }
683
684
685 uint64_t OrthancPluginDatabase::GetTotalUncompressedSize()
686 {
687 uint64_t size;
688 CheckSuccess(backend_.getTotalUncompressedSize(&size, payload_));
689 return size;
690 }
691
692
693 bool OrthancPluginDatabase::IsExistingResource(int64_t internalId)
694 {
695 int32_t existing;
696 CheckSuccess(backend_.isExistingResource(&existing, payload_, internalId));
697 return (existing != 0);
698 }
699
700
701 bool OrthancPluginDatabase::IsProtectedPatient(int64_t internalId)
702 {
703 int32_t isProtected;
704 CheckSuccess(backend_.isProtectedPatient(&isProtected, payload_, internalId));
705 return (isProtected != 0);
706 }
707
708
709 void OrthancPluginDatabase::ListAvailableAttachments(std::set<FileContentType>& target,
710 int64_t id)
711 {
712 ResetAnswers();
713
714 CheckSuccess(backend_.listAvailableAttachments(GetContext(), payload_, id));
715
716 if (type_ != _OrthancPluginDatabaseAnswerType_None &&
717 type_ != _OrthancPluginDatabaseAnswerType_Int32)
718 {
719 throw OrthancException(ErrorCode_DatabasePlugin);
720 }
721
722 target.clear();
723
724 if (type_ == _OrthancPluginDatabaseAnswerType_Int32)
725 {
726 for (std::list<int32_t>::const_iterator
727 it = answerInt32_.begin(); it != answerInt32_.end(); ++it)
728 {
729 target.insert(static_cast<FileContentType>(*it));
730 }
731 }
732 }
733
734
735 void OrthancPluginDatabase::LogChange(int64_t internalId,
736 const ServerIndexChange& change)
737 {
738 OrthancPluginChange tmp;
739 tmp.seq = change.GetSeq();
740 tmp.changeType = static_cast<int32_t>(change.GetChangeType());
741 tmp.resourceType = Plugins::Convert(change.GetResourceType());
742 tmp.publicId = change.GetPublicId().c_str();
743 tmp.date = change.GetDate().c_str();
744
745 CheckSuccess(backend_.logChange(payload_, &tmp));
746 }
747
748
749 void OrthancPluginDatabase::LogExportedResource(const ExportedResource& resource)
750 {
751 OrthancPluginExportedResource tmp;
752 tmp.seq = resource.GetSeq();
753 tmp.resourceType = Plugins::Convert(resource.GetResourceType());
754 tmp.publicId = resource.GetPublicId().c_str();
755 tmp.modality = resource.GetModality().c_str();
756 tmp.date = resource.GetDate().c_str();
757 tmp.patientId = resource.GetPatientId().c_str();
758 tmp.studyInstanceUid = resource.GetStudyInstanceUid().c_str();
759 tmp.seriesInstanceUid = resource.GetSeriesInstanceUid().c_str();
760 tmp.sopInstanceUid = resource.GetSopInstanceUid().c_str();
761
762 CheckSuccess(backend_.logExportedResource(payload_, &tmp));
763 }
764
765
766 bool OrthancPluginDatabase::LookupAttachment(FileInfo& attachment,
767 int64_t id,
768 FileContentType contentType)
769 {
770 ResetAnswers();
771
772 CheckSuccess(backend_.lookupAttachment
773 (GetContext(), payload_, id, static_cast<int32_t>(contentType)));
774
775 if (type_ == _OrthancPluginDatabaseAnswerType_None)
776 {
777 return false;
778 }
779 else if (type_ == _OrthancPluginDatabaseAnswerType_Attachment &&
780 answerAttachments_.size() == 1)
781 {
782 attachment = answerAttachments_.front();
783 return true;
784 }
785 else
786 {
787 throw OrthancException(ErrorCode_DatabasePlugin);
788 }
789 }
790
791
792 bool OrthancPluginDatabase::LookupGlobalProperty(std::string& target,
793 GlobalProperty property)
794 {
795 ResetAnswers();
796
797 CheckSuccess(backend_.lookupGlobalProperty
798 (GetContext(), payload_, static_cast<int32_t>(property)));
799
800 return ForwardSingleAnswer(target);
801 }
802
803
804 bool OrthancPluginDatabase::LookupMetadata(std::string& target,
805 int64_t id,
806 MetadataType type)
807 {
808 ResetAnswers();
809 CheckSuccess(backend_.lookupMetadata(GetContext(), payload_, id, static_cast<int32_t>(type)));
810 return ForwardSingleAnswer(target);
811 }
812
813
814 bool OrthancPluginDatabase::LookupParent(int64_t& parentId,
815 int64_t resourceId)
816 {
817 ResetAnswers();
818 CheckSuccess(backend_.lookupParent(GetContext(), payload_, resourceId));
819 return ForwardSingleAnswer(parentId);
820 }
821
822
823 bool OrthancPluginDatabase::LookupResource(int64_t& id,
824 ResourceType& type,
825 const std::string& publicId)
826 {
827 ResetAnswers();
828
829 CheckSuccess(backend_.lookupResource(GetContext(), payload_, publicId.c_str()));
830
831 if (type_ == _OrthancPluginDatabaseAnswerType_None)
832 {
833 return false;
834 }
835 else if (type_ == _OrthancPluginDatabaseAnswerType_Resource &&
836 answerResources_.size() == 1)
837 {
838 id = answerResources_.front().first;
839 type = answerResources_.front().second;
840 return true;
841 }
842 else
843 {
844 throw OrthancException(ErrorCode_DatabasePlugin);
845 }
846 }
847
848
849 bool OrthancPluginDatabase::SelectPatientToRecycle(int64_t& internalId)
850 {
851 ResetAnswers();
852 CheckSuccess(backend_.selectPatientToRecycle(GetContext(), payload_));
853 return ForwardSingleAnswer(internalId);
854 }
855
856
857 bool OrthancPluginDatabase::SelectPatientToRecycle(int64_t& internalId,
858 int64_t patientIdToAvoid)
859 {
860 ResetAnswers();
861 CheckSuccess(backend_.selectPatientToRecycle2(GetContext(), payload_, patientIdToAvoid));
862 return ForwardSingleAnswer(internalId);
863 }
864
865
866 void OrthancPluginDatabase::SetGlobalProperty(GlobalProperty property,
867 const std::string& value)
868 {
869 CheckSuccess(backend_.setGlobalProperty
870 (payload_, static_cast<int32_t>(property), value.c_str()));
871 }
872
873
874 void OrthancPluginDatabase::ClearMainDicomTags(int64_t id)
875 {
876 if (extensions_.clearMainDicomTags == NULL)
877 {
878 throw OrthancException(ErrorCode_DatabasePlugin,
879 "Your custom index plugin does not implement the mandatory ClearMainDicomTags() extension");
880 }
881
882 CheckSuccess(extensions_.clearMainDicomTags(payload_, id));
883 }
884
885
886 void OrthancPluginDatabase::SetMainDicomTag(int64_t id,
887 const DicomTag& tag,
888 const std::string& value)
889 {
890 OrthancPluginDicomTag tmp;
891 tmp.group = tag.GetGroup();
892 tmp.element = tag.GetElement();
893 tmp.value = value.c_str();
894
895 CheckSuccess(backend_.setMainDicomTag(payload_, id, &tmp));
896 }
897
898
899 void OrthancPluginDatabase::SetIdentifierTag(int64_t id,
900 const DicomTag& tag,
901 const std::string& value)
902 {
903 OrthancPluginDicomTag tmp;
904 tmp.group = tag.GetGroup();
905 tmp.element = tag.GetElement();
906 tmp.value = value.c_str();
907
908 CheckSuccess(backend_.setIdentifierTag(payload_, id, &tmp));
909 }
910
911
912 void OrthancPluginDatabase::SetMetadata(int64_t id,
913 MetadataType type,
914 const std::string& value)
915 {
916 CheckSuccess(backend_.setMetadata
917 (payload_, id, static_cast<int32_t>(type), value.c_str()));
918 }
919
920
921 void OrthancPluginDatabase::SetProtectedPatient(int64_t internalId,
922 bool isProtected)
923 {
924 CheckSuccess(backend_.setProtectedPatient(payload_, internalId, isProtected));
925 } 1222 }
926 1223
927 1224
928 IDatabaseWrapper::ITransaction* OrthancPluginDatabase::StartTransaction(TransactionType type, 1225 IDatabaseWrapper::ITransaction* OrthancPluginDatabase::StartTransaction(TransactionType type,
929 IDatabaseListener& listener) 1226 IDatabaseListener& listener)
988 1285
989 1286
990 void OrthancPluginDatabase::Upgrade(unsigned int targetVersion, 1287 void OrthancPluginDatabase::Upgrade(unsigned int targetVersion,
991 IStorageArea& storageArea) 1288 IStorageArea& storageArea)
992 { 1289 {
993 VoidListener listener; 1290 VoidDatabaseListener listener;
994 1291
995 if (extensions_.upgradeDatabase != NULL) 1292 if (extensions_.upgradeDatabase != NULL)
996 { 1293 {
997 Transaction transaction(*this, listener); 1294 Transaction transaction(*this, listener);
998 transaction.Begin(); 1295 transaction.Begin();
1265 throw OrthancException(ErrorCode_DatabasePlugin, 1562 throw OrthancException(ErrorCode_DatabasePlugin,
1266 "Unhandled type of answer for custom index plugin: " + 1563 "Unhandled type of answer for custom index plugin: " +
1267 boost::lexical_cast<std::string>(answer.type)); 1564 boost::lexical_cast<std::string>(answer.type));
1268 } 1565 }
1269 } 1566 }
1270
1271
1272 bool OrthancPluginDatabase::IsDiskSizeAbove(uint64_t threshold)
1273 {
1274 if (fastGetTotalSize_)
1275 {
1276 return GetTotalCompressedSize() > threshold;
1277 }
1278 else
1279 {
1280 assert(GetTotalCompressedSize() == currentDiskSize_);
1281 return currentDiskSize_ > threshold;
1282 }
1283 }
1284
1285
1286 void OrthancPluginDatabase::ApplyLookupResources(std::list<std::string>& resourcesId,
1287 std::list<std::string>* instancesId,
1288 const std::vector<DatabaseConstraint>& lookup,
1289 ResourceType queryLevel,
1290 size_t limit)
1291 {
1292 if (extensions_.lookupResources == NULL)
1293 {
1294 // Fallback to compatibility mode
1295 ILookupResources::Apply
1296 (*this, *this, resourcesId, instancesId, lookup, queryLevel, limit);
1297 }
1298 else
1299 {
1300 std::vector<OrthancPluginDatabaseConstraint> constraints;
1301 std::vector< std::vector<const char*> > constraintsValues;
1302
1303 constraints.resize(lookup.size());
1304 constraintsValues.resize(lookup.size());
1305
1306 for (size_t i = 0; i < lookup.size(); i++)
1307 {
1308 lookup[i].EncodeForPlugins(constraints[i], constraintsValues[i]);
1309 }
1310
1311 ResetAnswers();
1312 answerMatchingResources_ = &resourcesId;
1313 answerMatchingInstances_ = instancesId;
1314
1315 CheckSuccess(extensions_.lookupResources(GetContext(), payload_, lookup.size(),
1316 (lookup.empty() ? NULL : &constraints[0]),
1317 Plugins::Convert(queryLevel),
1318 limit, (instancesId == NULL ? 0 : 1)));
1319 }
1320 }
1321
1322
1323 bool OrthancPluginDatabase::CreateInstance(
1324 IDatabaseWrapper::CreateInstanceResult& result,
1325 int64_t& instanceId,
1326 const std::string& patient,
1327 const std::string& study,
1328 const std::string& series,
1329 const std::string& instance)
1330 {
1331 if (extensions_.createInstance == NULL)
1332 {
1333 // Fallback to compatibility mode
1334 return ICreateInstance::Apply
1335 (*this, result, instanceId, patient, study, series, instance);
1336 }
1337 else
1338 {
1339 OrthancPluginCreateInstanceResult output;
1340 memset(&output, 0, sizeof(output));
1341
1342 CheckSuccess(extensions_.createInstance(&output, payload_, patient.c_str(),
1343 study.c_str(), series.c_str(), instance.c_str()));
1344
1345 instanceId = output.instanceId;
1346
1347 if (output.isNewInstance)
1348 {
1349 result.isNewPatient_ = output.isNewPatient;
1350 result.isNewStudy_ = output.isNewStudy;
1351 result.isNewSeries_ = output.isNewSeries;
1352 result.patientId_ = output.patientId;
1353 result.studyId_ = output.studyId;
1354 result.seriesId_ = output.seriesId;
1355 return true;
1356 }
1357 else
1358 {
1359 return false;
1360 }
1361 }
1362 }
1363
1364
1365 void OrthancPluginDatabase::LookupIdentifier(std::list<int64_t>& result,
1366 ResourceType level,
1367 const DicomTag& tag,
1368 Compatibility::IdentifierConstraintType type,
1369 const std::string& value)
1370 {
1371 if (extensions_.lookupIdentifier3 == NULL)
1372 {
1373 throw OrthancException(ErrorCode_DatabasePlugin,
1374 "The database plugin does not implement the mandatory LookupIdentifier3() extension");
1375 }
1376
1377 OrthancPluginDicomTag tmp;
1378 tmp.group = tag.GetGroup();
1379 tmp.element = tag.GetElement();
1380 tmp.value = value.c_str();
1381
1382 ResetAnswers();
1383 CheckSuccess(extensions_.lookupIdentifier3(GetContext(), payload_, Plugins::Convert(level),
1384 &tmp, Compatibility::Convert(type)));
1385 ForwardAnswers(result);
1386 }
1387
1388
1389 void OrthancPluginDatabase::LookupIdentifierRange(std::list<int64_t>& result,
1390 ResourceType level,
1391 const DicomTag& tag,
1392 const std::string& start,
1393 const std::string& end)
1394 {
1395 if (extensions_.lookupIdentifierRange == NULL)
1396 {
1397 // Default implementation, for plugins using Orthanc SDK <= 1.3.2
1398
1399 LookupIdentifier(result, level, tag, Compatibility::IdentifierConstraintType_GreaterOrEqual, start);
1400
1401 std::list<int64_t> b;
1402 LookupIdentifier(result, level, tag, Compatibility::IdentifierConstraintType_SmallerOrEqual, end);
1403
1404 result.splice(result.end(), b);
1405 }
1406 else
1407 {
1408 ResetAnswers();
1409 CheckSuccess(extensions_.lookupIdentifierRange(GetContext(), payload_, Plugins::Convert(level),
1410 tag.GetGroup(), tag.GetElement(),
1411 start.c_str(), end.c_str()));
1412 ForwardAnswers(result);
1413 }
1414 }
1415
1416
1417 void OrthancPluginDatabase::SetResourcesContent(const Orthanc::ResourcesContent& content)
1418 {
1419 if (extensions_.setResourcesContent == NULL)
1420 {
1421 ISetResourcesContent::Apply(*this, content);
1422 }
1423 else
1424 {
1425 std::vector<OrthancPluginResourcesContentTags> identifierTags;
1426 std::vector<OrthancPluginResourcesContentTags> mainDicomTags;
1427 std::vector<OrthancPluginResourcesContentMetadata> metadata;
1428
1429 identifierTags.reserve(content.GetListTags().size());
1430 mainDicomTags.reserve(content.GetListTags().size());
1431 metadata.reserve(content.GetListMetadata().size());
1432
1433 for (ResourcesContent::ListTags::const_iterator
1434 it = content.GetListTags().begin(); it != content.GetListTags().end(); ++it)
1435 {
1436 OrthancPluginResourcesContentTags tmp;
1437 tmp.resource = it->resourceId_;
1438 tmp.group = it->tag_.GetGroup();
1439 tmp.element = it->tag_.GetElement();
1440 tmp.value = it->value_.c_str();
1441
1442 if (it->isIdentifier_)
1443 {
1444 identifierTags.push_back(tmp);
1445 }
1446 else
1447 {
1448 mainDicomTags.push_back(tmp);
1449 }
1450 }
1451
1452 for (ResourcesContent::ListMetadata::const_iterator
1453 it = content.GetListMetadata().begin(); it != content.GetListMetadata().end(); ++it)
1454 {
1455 OrthancPluginResourcesContentMetadata tmp;
1456 tmp.resource = it->resourceId_;
1457 tmp.metadata = it->metadata_;
1458 tmp.value = it->value_.c_str();
1459 metadata.push_back(tmp);
1460 }
1461
1462 assert(identifierTags.size() + mainDicomTags.size() == content.GetListTags().size() &&
1463 metadata.size() == content.GetListMetadata().size());
1464
1465 CheckSuccess(extensions_.setResourcesContent(
1466 payload_,
1467 identifierTags.size(),
1468 (identifierTags.empty() ? NULL : &identifierTags[0]),
1469 mainDicomTags.size(),
1470 (mainDicomTags.empty() ? NULL : &mainDicomTags[0]),
1471 metadata.size(),
1472 (metadata.empty() ? NULL : &metadata[0])));
1473 }
1474 }
1475
1476
1477
1478 void OrthancPluginDatabase::GetChildrenMetadata(std::list<std::string>& target,
1479 int64_t resourceId,
1480 MetadataType metadata)
1481 {
1482 if (extensions_.getChildrenMetadata == NULL)
1483 {
1484 IGetChildrenMetadata::Apply(*this, target, resourceId, metadata);
1485 }
1486 else
1487 {
1488 ResetAnswers();
1489 CheckSuccess(extensions_.getChildrenMetadata
1490 (GetContext(), payload_, resourceId, static_cast<int32_t>(metadata)));
1491 ForwardAnswers(target);
1492 }
1493 }
1494
1495
1496 int64_t OrthancPluginDatabase::GetLastChangeIndex()
1497 {
1498 if (extensions_.getLastChangeIndex == NULL)
1499 {
1500 // This was the default behavior in Orthanc <= 1.5.1
1501 // https://groups.google.com/d/msg/orthanc-users/QhzB6vxYeZ0/YxabgqpfBAAJ
1502 return 0;
1503 }
1504 else
1505 {
1506 int64_t result = 0;
1507 CheckSuccess(extensions_.getLastChangeIndex(&result, payload_));
1508 return result;
1509 }
1510 }
1511
1512
1513 void OrthancPluginDatabase::TagMostRecentPatient(int64_t patient)
1514 {
1515 if (extensions_.tagMostRecentPatient != NULL)
1516 {
1517 CheckSuccess(extensions_.tagMostRecentPatient(payload_, patient));
1518 }
1519 }
1520
1521
1522 bool OrthancPluginDatabase::LookupResourceAndParent(int64_t& id,
1523 ResourceType& type,
1524 std::string& parentPublicId,
1525 const std::string& publicId)
1526 {
1527 if (extensions_.lookupResourceAndParent == NULL)
1528 {
1529 return ILookupResourceAndParent::Apply(*this, id, type, parentPublicId, publicId);
1530 }
1531 else
1532 {
1533 std::list<std::string> parent;
1534
1535 uint8_t isExisting;
1536 OrthancPluginResourceType pluginType = OrthancPluginResourceType_Patient;
1537
1538 ResetAnswers();
1539 CheckSuccess(extensions_.lookupResourceAndParent
1540 (GetContext(), &isExisting, &id, &pluginType, payload_, publicId.c_str()));
1541 ForwardAnswers(parent);
1542
1543 if (isExisting)
1544 {
1545 type = Plugins::Convert(pluginType);
1546
1547 if (parent.empty())
1548 {
1549 if (type != ResourceType_Patient)
1550 {
1551 throw OrthancException(ErrorCode_DatabasePlugin);
1552 }
1553 }
1554 else if (parent.size() == 1)
1555 {
1556 if ((type != ResourceType_Study &&
1557 type != ResourceType_Series &&
1558 type != ResourceType_Instance) ||
1559 parent.front().empty())
1560 {
1561 throw OrthancException(ErrorCode_DatabasePlugin);
1562 }
1563
1564 parentPublicId = parent.front();
1565 }
1566 else
1567 {
1568 throw OrthancException(ErrorCode_DatabasePlugin);
1569 }
1570
1571 return true;
1572 }
1573 else
1574 {
1575 return false;
1576 }
1577 }
1578 }
1579 } 1567 }