Mercurial > hg > orthanc-databases
diff Framework/Plugins/DatabaseBackendAdapterV4.cpp @ 569:f18e46d7dbf8 attach-custom-data
merged find-refactoring -> attach-custom-data
author | Alain Mazy <am@orthanc.team> |
---|---|
date | Tue, 24 Sep 2024 15:04:21 +0200 |
parents | cd9521e04249 77c8544bbd7d |
children |
line wrap: on
line diff
--- a/Framework/Plugins/DatabaseBackendAdapterV4.cpp Wed Feb 01 16:24:37 2023 +0100 +++ b/Framework/Plugins/DatabaseBackendAdapterV4.cpp Tue Sep 24 15:04:21 2024 +0200 @@ -2,7 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2021 Osimis S.A., Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -24,8 +26,12 @@ #if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE) // Macro introduced in Orthanc 1.3.1 # if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 12, 0) +#include "IndexConnectionsPool.h" +#include "MessagesToolbox.h" + +#include <OrthancDatabasePlugin.pb.h> // Include protobuf messages + #include <Logging.h> -#include <MultiThreading/SharedMessageQueue.h> #include <OrthancException.h> #include <stdexcept> @@ -34,550 +40,155 @@ #include <cassert> -#define ORTHANC_PLUGINS_DATABASE_CATCH(context) \ - catch (::Orthanc::OrthancException& e) \ - { \ - return static_cast<OrthancPluginErrorCode>(e.GetErrorCode()); \ - } \ - catch (::std::runtime_error& e) \ - { \ - const std::string message = "Exception in database back-end: " + std::string(e.what()); \ - OrthancPluginLogError(context, message.c_str()); \ - return OrthancPluginErrorCode_DatabasePlugin; \ - } \ - catch (...) \ - { \ - OrthancPluginLogError(context, "Native exception"); \ - return OrthancPluginErrorCode_DatabasePlugin; \ - } +#define ORTHANC_PLUGINS_DATABASE_CATCH(context) \ namespace OrthancDatabases { static bool isBackendInUse_ = false; // Only for sanity checks - - template <typename T> - static void CopyListToVector(std::vector<T>& target, - const std::list<T>& source) + + static Orthanc::DatabasePluginMessages::ResourceType Convert(OrthancPluginResourceType resourceType) { - /** - * This has the the same effect as: - * - * target.reserve(source.size()); - * std::copy(std::begin(source), std::end(source), std::back_inserter(target)); - * - * However, this implementation is compatible with C++03 (Linux - * Standard Base), whereas "std::back_inserter" requires C++11. - **/ + switch (resourceType) + { + case OrthancPluginResourceType_Patient: + return Orthanc::DatabasePluginMessages::RESOURCE_PATIENT; + + case OrthancPluginResourceType_Study: + return Orthanc::DatabasePluginMessages::RESOURCE_STUDY; - target.clear(); - target.reserve(source.size()); + case OrthancPluginResourceType_Series: + return Orthanc::DatabasePluginMessages::RESOURCE_SERIES; - for (typename std::list<T>::const_iterator it = source.begin(); it != source.end(); ++it) - { - target.push_back(*it); + case OrthancPluginResourceType_Instance: + return Orthanc::DatabasePluginMessages::RESOURCE_INSTANCE; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); } } - - - class DatabaseBackendAdapterV4::Adapter : public boost::noncopyable + + + static OrthancPluginResourceType Convert(Orthanc::DatabasePluginMessages::ResourceType resourceType) + { + switch (resourceType) + { + case Orthanc::DatabasePluginMessages::RESOURCE_PATIENT: + return OrthancPluginResourceType_Patient; + + case Orthanc::DatabasePluginMessages::RESOURCE_STUDY: + return OrthancPluginResourceType_Study; + + case Orthanc::DatabasePluginMessages::RESOURCE_SERIES: + return OrthancPluginResourceType_Series; + + case Orthanc::DatabasePluginMessages::RESOURCE_INSTANCE: + return OrthancPluginResourceType_Instance; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + } + + + class Output : public IDatabaseBackendOutput { private: - class ManagerReference : public Orthanc::IDynamicObject - { - private: - DatabaseManager* manager_; - - public: - ManagerReference(DatabaseManager& manager) : - manager_(&manager) - { - } - - DatabaseManager& GetManager() - { - assert(manager_ != NULL); - return *manager_; - } - }; - - std::unique_ptr<IndexBackend> backend_; - OrthancPluginContext* context_; - boost::shared_mutex connectionsMutex_; - size_t countConnections_; - std::list<DatabaseManager*> connections_; - Orthanc::SharedMessageQueue availableConnections_; - - public: - Adapter(IndexBackend* backend, - size_t countConnections) : - backend_(backend), - countConnections_(countConnections) - { - if (countConnections == 0) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange, - "There must be a non-zero number of connections to the database"); - } - else if (backend == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); - } - else - { - context_ = backend_->GetContext(); - } - } - - ~Adapter() - { - for (std::list<DatabaseManager*>::iterator - it = connections_.begin(); it != connections_.end(); ++it) - { - assert(*it != NULL); - delete *it; - } - } - - OrthancPluginContext* GetContext() const - { - return context_; - } - - void OpenConnections() - { - boost::unique_lock<boost::shared_mutex> lock(connectionsMutex_); - - if (connections_.size() == 0) - { - assert(backend_.get() != NULL); - - { - std::unique_ptr<DatabaseManager> manager(new DatabaseManager(backend_->CreateDatabaseFactory())); - manager->GetDatabase(); // Make sure to open the database connection - - backend_->ConfigureDatabase(*manager); - connections_.push_back(manager.release()); - } - - for (size_t i = 1; i < countConnections_; i++) - { - connections_.push_back(new DatabaseManager(backend_->CreateDatabaseFactory())); - connections_.back()->GetDatabase(); // Make sure to open the database connection - } - - for (std::list<DatabaseManager*>::iterator - it = connections_.begin(); it != connections_.end(); ++it) - { - assert(*it != NULL); - availableConnections_.Enqueue(new ManagerReference(**it)); - } - } - else - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - } - - void CloseConnections() - { - boost::unique_lock<boost::shared_mutex> lock(connectionsMutex_); + Orthanc::DatabasePluginMessages::DeleteAttachment::Response* deleteAttachment_; + Orthanc::DatabasePluginMessages::DeleteResource::Response* deleteResource_; + Orthanc::DatabasePluginMessages::GetChanges::Response* getChanges_; + Orthanc::DatabasePluginMessages::GetExportedResources::Response* getExportedResources_; + Orthanc::DatabasePluginMessages::GetLastChange::Response* getLastChange_; + Orthanc::DatabasePluginMessages::GetLastExportedResource::Response* getLastExportedResource_; + Orthanc::DatabasePluginMessages::GetMainDicomTags::Response* getMainDicomTags_; + Orthanc::DatabasePluginMessages::LookupAttachment::Response* lookupAttachment_; + Orthanc::DatabasePluginMessages::LookupResources::Response* lookupResources_; - if (connections_.size() != countConnections_) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - else if (availableConnections_.GetSize() != countConnections_) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_Database, "Some connections are still in use, bug in the Orthanc core"); - } - else - { - for (std::list<DatabaseManager*>::iterator - it = connections_.begin(); it != connections_.end(); ++it) - { - assert(*it != NULL); - (*it)->Close(); - } - } - } - - class DatabaseAccessor : public boost::noncopyable - { - private: - boost::shared_lock<boost::shared_mutex> lock_; - Adapter& adapter_; - DatabaseManager* manager_; - - public: - DatabaseAccessor(Adapter& adapter) : - lock_(adapter.connectionsMutex_), - adapter_(adapter), - manager_(NULL) - { - for (;;) - { - std::unique_ptr<Orthanc::IDynamicObject> manager(adapter.availableConnections_.Dequeue(100)); - if (manager.get() != NULL) - { - manager_ = &dynamic_cast<ManagerReference&>(*manager).GetManager(); - return; - } - } - } - - ~DatabaseAccessor() - { - assert(manager_ != NULL); - adapter_.availableConnections_.Enqueue(new ManagerReference(*manager_)); - } - - IndexBackend& GetBackend() const - { - return *adapter_.backend_; - } - - DatabaseManager& GetManager() const - { - assert(manager_ != NULL); - return *manager_; - } - }; - }; - - - class DatabaseBackendAdapterV4::Output : public IDatabaseBackendOutput - { - private: - struct Metadata - { - int32_t metadata; - const char* value; - }; - - _OrthancPluginDatabaseAnswerType answerType_; - std::list<std::string> stringsStore_; - - std::vector<OrthancPluginAttachment2> attachments_; - std::vector<OrthancPluginChange> changes_; - std::vector<OrthancPluginDicomTag> tags_; - std::vector<OrthancPluginExportedResource> exported_; - std::vector<OrthancPluginDatabaseEvent2> events_; - std::vector<int32_t> integers32_; - std::vector<int64_t> integers64_; - std::vector<OrthancPluginMatchingResource> matches_; - std::vector<Metadata> metadata_; - std::vector<std::string> stringAnswers_; - - const char* StoreString(const std::string& s) - { - stringsStore_.push_back(s); - return stringsStore_.back().c_str(); - } - - void SetupAnswerType(_OrthancPluginDatabaseAnswerType type) - { - if (answerType_ == _OrthancPluginDatabaseAnswerType_None) - { - answerType_ = type; - } - else if (answerType_ != type) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - } - - public: - Output() : - answerType_(_OrthancPluginDatabaseAnswerType_None) - { - } +#if ORTHANC_PLUGINS_HAS_CHANGES_EXTENDED == 1 + Orthanc::DatabasePluginMessages::GetChangesExtended::Response* getChangesExtended_; +#endif void Clear() { - // We don't systematically clear all the vectors, in order to - // avoid spending unnecessary time - - switch (answerType_) - { - case _OrthancPluginDatabaseAnswerType_None: - break; - - case _OrthancPluginDatabaseAnswerType_Attachment: - attachments_.clear(); - break; - - case _OrthancPluginDatabaseAnswerType_Change: - changes_.clear(); - break; - - case _OrthancPluginDatabaseAnswerType_DicomTag: - tags_.clear(); - break; - - case _OrthancPluginDatabaseAnswerType_ExportedResource: - exported_.clear(); - break; - - case _OrthancPluginDatabaseAnswerType_Int32: - integers32_.clear(); - break; - - case _OrthancPluginDatabaseAnswerType_Int64: - integers64_.clear(); - break; - - case _OrthancPluginDatabaseAnswerType_MatchingResource: - matches_.clear(); - break; - - case _OrthancPluginDatabaseAnswerType_Metadata: - metadata_.clear(); - break; - - case _OrthancPluginDatabaseAnswerType_String: - stringAnswers_.clear(); - break; - - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - - answerType_ = _OrthancPluginDatabaseAnswerType_None; - stringsStore_.clear(); - events_.clear(); - - assert(attachments_.empty()); - assert(changes_.empty()); - assert(tags_.empty()); - assert(exported_.empty()); - assert(events_.empty()); - assert(integers32_.empty()); - assert(integers64_.empty()); - assert(matches_.empty()); - assert(metadata_.empty()); - assert(stringAnswers_.empty()); - } - + deleteAttachment_ = NULL; + deleteResource_ = NULL; + getChanges_ = NULL; + getExportedResources_ = NULL; + getLastChange_ = NULL; + getLastExportedResource_ = NULL; + getMainDicomTags_ = NULL; + lookupAttachment_ = NULL; + lookupResources_ = NULL; - OrthancPluginErrorCode ReadAnswersCount(uint32_t& target) const +#if ORTHANC_PLUGINS_HAS_CHANGES_EXTENDED == 1 + getChangesExtended_ = NULL; +#endif + } + + public: + Output(Orthanc::DatabasePluginMessages::DeleteAttachment::Response& deleteAttachment) { - switch (answerType_) - { - case _OrthancPluginDatabaseAnswerType_None: - target = static_cast<uint32_t>(0); - break; - - case _OrthancPluginDatabaseAnswerType_Attachment: - target = static_cast<uint32_t>(attachments_.size()); - break; - - case _OrthancPluginDatabaseAnswerType_Change: - target = static_cast<uint32_t>(changes_.size()); - break; - - case _OrthancPluginDatabaseAnswerType_DicomTag: - target = static_cast<uint32_t>(tags_.size()); - break; - - case _OrthancPluginDatabaseAnswerType_ExportedResource: - target = static_cast<uint32_t>(exported_.size()); - break; - - case _OrthancPluginDatabaseAnswerType_Int32: - target = static_cast<uint32_t>(integers32_.size()); - break; - - case _OrthancPluginDatabaseAnswerType_Int64: - target = static_cast<uint32_t>(integers64_.size()); - break; - - case _OrthancPluginDatabaseAnswerType_MatchingResource: - target = static_cast<uint32_t>(matches_.size()); - break; - - case _OrthancPluginDatabaseAnswerType_Metadata: - target = static_cast<uint32_t>(metadata_.size()); - break; - - case _OrthancPluginDatabaseAnswerType_String: - target = static_cast<uint32_t>(stringAnswers_.size()); - break; - - default: - return OrthancPluginErrorCode_InternalError; - } - - return OrthancPluginErrorCode_Success; + Clear(); + deleteAttachment_ = &deleteAttachment; } - - - OrthancPluginErrorCode ReadAnswerAttachment2(OrthancPluginAttachment2& target /* out */, - uint32_t index) const + + Output(Orthanc::DatabasePluginMessages::DeleteResource::Response& deleteResource) { - if (index < attachments_.size()) - { - target = attachments_[index]; - return OrthancPluginErrorCode_Success; - } - else - { - return OrthancPluginErrorCode_ParameterOutOfRange; - } + Clear(); + deleteResource_ = &deleteResource; + } + + Output(Orthanc::DatabasePluginMessages::GetChanges::Response& getChanges) + { + Clear(); + getChanges_ = &getChanges; } - - OrthancPluginErrorCode ReadAnswerChange(OrthancPluginChange& target /* out */, - uint32_t index) const +#if ORTHANC_PLUGINS_HAS_CHANGES_EXTENDED == 1 + Output(Orthanc::DatabasePluginMessages::GetChangesExtended::Response& getChangesExtended) { - if (index < changes_.size()) - { - target = changes_[index]; - return OrthancPluginErrorCode_Success; - } - else - { - return OrthancPluginErrorCode_ParameterOutOfRange; - } - } - - - OrthancPluginErrorCode ReadAnswerDicomTag(uint16_t& group, - uint16_t& element, - const char*& value, - uint32_t index) const - { - if (index < tags_.size()) - { - const OrthancPluginDicomTag& tag = tags_[index]; - group = tag.group; - element = tag.element; - value = tag.value; - return OrthancPluginErrorCode_Success; - } - else - { - return OrthancPluginErrorCode_ParameterOutOfRange; - } + Clear(); + getChangesExtended_ = &getChangesExtended; } - - - OrthancPluginErrorCode ReadAnswerExportedResource(OrthancPluginExportedResource& target /* out */, - uint32_t index) const - { - if (index < exported_.size()) - { - target = exported_[index]; - return OrthancPluginErrorCode_Success; - } - else - { - return OrthancPluginErrorCode_ParameterOutOfRange; - } - } - +#endif - OrthancPluginErrorCode ReadAnswerInt32(int32_t& target, - uint32_t index) const + Output(Orthanc::DatabasePluginMessages::GetExportedResources::Response& getExportedResources) { - if (index < integers32_.size()) - { - target = integers32_[index]; - return OrthancPluginErrorCode_Success; - } - else - { - return OrthancPluginErrorCode_ParameterOutOfRange; - } + Clear(); + getExportedResources_ = &getExportedResources; } - - - OrthancPluginErrorCode ReadAnswerInt64(int64_t& target, - uint32_t index) const + + Output(Orthanc::DatabasePluginMessages::GetLastChange::Response& getLastChange) + { + Clear(); + getLastChange_ = &getLastChange; + } + + Output(Orthanc::DatabasePluginMessages::GetLastExportedResource::Response& getLastExportedResource) { - if (index < integers64_.size()) - { - target = integers64_[index]; - return OrthancPluginErrorCode_Success; - } - else - { - return OrthancPluginErrorCode_ParameterOutOfRange; - } + Clear(); + getLastExportedResource_ = &getLastExportedResource; } - - - OrthancPluginErrorCode ReadAnswerMatchingResource(OrthancPluginMatchingResource& target, - uint32_t index) const - { - if (index < matches_.size()) - { - target = matches_[index]; - return OrthancPluginErrorCode_Success; - } - else - { - return OrthancPluginErrorCode_ParameterOutOfRange; - } - } - - - OrthancPluginErrorCode ReadAnswerMetadata(int32_t& metadata, - const char*& value, - uint32_t index) const + + Output(Orthanc::DatabasePluginMessages::GetMainDicomTags::Response& getMainDicomTags) { - if (index < metadata_.size()) - { - const Metadata& tmp = metadata_[index]; - metadata = tmp.metadata; - value = tmp.value; - return OrthancPluginErrorCode_Success; - } - else - { - return OrthancPluginErrorCode_ParameterOutOfRange; - } + Clear(); + getMainDicomTags_ = &getMainDicomTags; } - - - OrthancPluginErrorCode ReadAnswerString(const char*& target, - uint32_t index) const + + Output(Orthanc::DatabasePluginMessages::LookupAttachment::Response& lookupAttachment) { - if (index < stringAnswers_.size()) - { - target = stringAnswers_[index].c_str(); - return OrthancPluginErrorCode_Success; - } - else - { - return OrthancPluginErrorCode_ParameterOutOfRange; - } - } - - - OrthancPluginErrorCode ReadEventsCount(uint32_t& target /* out */) const - { - target = static_cast<uint32_t>(events_.size()); - return OrthancPluginErrorCode_Success; + Clear(); + lookupAttachment_ = &lookupAttachment; } - - OrthancPluginErrorCode ReadEvent2(OrthancPluginDatabaseEvent2& event /* out */, - uint32_t index) const + Output(Orthanc::DatabasePluginMessages::LookupResources::Response& lookupResources) { - if (index < events_.size()) - { - event = events_[index]; - return OrthancPluginErrorCode_Success; - } - else - { - return OrthancPluginErrorCode_ParameterOutOfRange; - } + Clear(); + lookupResources_ = &lookupResources; } - - + virtual void SignalDeletedAttachment(const std::string& uuid, int32_t contentType, uint64_t uncompressedSize, @@ -587,45 +198,72 @@ const std::string& compressedHash, const std::string& customData) ORTHANC_OVERRIDE { - OrthancPluginDatabaseEvent2 event; - event.type = OrthancPluginDatabaseEventType_DeletedAttachment; - event.content.attachment.uuid = StoreString(uuid); - event.content.attachment.contentType = contentType; - event.content.attachment.uncompressedSize = uncompressedSize; - event.content.attachment.uncompressedHash = StoreString(uncompressedHash); - event.content.attachment.compressionType = compressionType; - event.content.attachment.compressedSize = compressedSize; - event.content.attachment.compressedHash = StoreString(compressedHash); - event.content.attachment.customData = StoreString(customData); + Orthanc::DatabasePluginMessages::FileInfo* attachment; + + if (deleteAttachment_ != NULL) + { + if (deleteAttachment_->has_deleted_attachment()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } - events_.push_back(event); + attachment = deleteAttachment_->mutable_deleted_attachment(); + } + else if (deleteResource_ != NULL) + { + attachment = deleteResource_->add_deleted_attachments(); + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + + attachment->set_uuid(uuid); + attachment->set_content_type(contentType); + attachment->set_uncompressed_size(uncompressedSize); + attachment->set_uncompressed_hash(uncompressedHash); + attachment->set_compression_type(compressionType); + attachment->set_compressed_size(compressedSize); + attachment->set_compressed_hash(compressedHash); } - - + virtual void SignalDeletedResource(const std::string& publicId, OrthancPluginResourceType resourceType) ORTHANC_OVERRIDE { - OrthancPluginDatabaseEvent2 event; - event.type = OrthancPluginDatabaseEventType_DeletedResource; - event.content.resource.level = resourceType; - event.content.resource.publicId = StoreString(publicId); - - events_.push_back(event); + if (deleteResource_ != NULL) + { + Orthanc::DatabasePluginMessages::DeleteResource_Response_Resource* resource = deleteResource_->add_deleted_resources(); + resource->set_level(Convert(resourceType)); + resource->set_public_id(publicId); + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } } - virtual void SignalRemainingAncestor(const std::string& ancestorId, OrthancPluginResourceType ancestorType) ORTHANC_OVERRIDE { - OrthancPluginDatabaseEvent2 event; - event.type = OrthancPluginDatabaseEventType_RemainingAncestor; - event.content.resource.level = ancestorType; - event.content.resource.publicId = StoreString(ancestorId); - - events_.push_back(event); + if (deleteResource_ != NULL) + { + if (deleteResource_->is_remaining_ancestor()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + else + { + deleteResource_->set_is_remaining_ancestor(true); + deleteResource_->mutable_remaining_ancestor()->set_level(Convert(ancestorType)); + deleteResource_->mutable_remaining_ancestor()->set_public_id(ancestorId); + } + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } } - virtual void AnswerAttachment(const std::string& uuid, int32_t contentType, uint64_t uncompressedSize, @@ -635,21 +273,27 @@ const std::string& compressedHash, const std::string& customData) ORTHANC_OVERRIDE { - SetupAnswerType(_OrthancPluginDatabaseAnswerType_Attachment); + if (lookupAttachment_ != NULL) + { + if (lookupAttachment_->found()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } - OrthancPluginAttachment2 attachment; - attachment.uuid = StoreString(uuid); - attachment.contentType = contentType; - attachment.uncompressedSize = uncompressedSize; - attachment.uncompressedHash = StoreString(uncompressedHash); - attachment.compressionType = compressionType; - attachment.compressedSize = compressedSize; - attachment.compressedHash = StoreString(compressedHash); - attachment.customData = StoreString(customData); - - attachments_.push_back(attachment); + lookupAttachment_->set_found(true); + lookupAttachment_->mutable_attachment()->set_uuid(uuid); + lookupAttachment_->mutable_attachment()->set_content_type(contentType); + lookupAttachment_->mutable_attachment()->set_uncompressed_size(uncompressedSize); + lookupAttachment_->mutable_attachment()->set_uncompressed_hash(uncompressedHash); + lookupAttachment_->mutable_attachment()->set_compression_type(compressionType); + lookupAttachment_->mutable_attachment()->set_compressed_size(compressedSize); + lookupAttachment_->mutable_attachment()->set_compressed_hash(compressedHash); + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } } - virtual void AnswerChange(int64_t seq, int32_t changeType, @@ -657,33 +301,56 @@ const std::string& publicId, const std::string& date) ORTHANC_OVERRIDE { - SetupAnswerType(_OrthancPluginDatabaseAnswerType_Change); + Orthanc::DatabasePluginMessages::ServerIndexChange* change; + + if (getChanges_ != NULL) + { + change = getChanges_->add_changes(); + } +#if ORTHANC_PLUGINS_HAS_CHANGES_EXTENDED == 1 + else if (getChangesExtended_ != NULL) + { + change = getChangesExtended_->add_changes(); + } +#endif + else if (getLastChange_ != NULL) + { + if (getLastChange_->found()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } - OrthancPluginChange change; - change.seq = seq; - change.changeType = changeType; - change.resourceType = resourceType; - change.publicId = StoreString(publicId); - change.date = StoreString(date); + getLastChange_->set_found(true); + change = getLastChange_->mutable_change(); + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } - changes_.push_back(change); + change->set_seq(seq); + change->set_change_type(changeType); + change->set_resource_type(Convert(resourceType)); + change->set_public_id(publicId); + change->set_date(date); } - virtual void AnswerDicomTag(uint16_t group, uint16_t element, const std::string& value) ORTHANC_OVERRIDE { - SetupAnswerType(_OrthancPluginDatabaseAnswerType_DicomTag); - - OrthancPluginDicomTag tag; - tag.group = group; - tag.element = element; - tag.value = StoreString(value); - - tags_.push_back(tag); + if (getMainDicomTags_ != NULL) + { + Orthanc::DatabasePluginMessages::GetMainDicomTags_Response_Tag* tag = getMainDicomTags_->add_tags(); + tag->set_group(group); + tag->set_element(element); + tag->set_value(value); + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } } - virtual void AnswerExportedResource(int64_t seq, OrthancPluginResourceType resourceType, @@ -695,98 +362,57 @@ const std::string& seriesInstanceUid, const std::string& sopInstanceUid) ORTHANC_OVERRIDE { - SetupAnswerType(_OrthancPluginDatabaseAnswerType_ExportedResource); + Orthanc::DatabasePluginMessages::ExportedResource* resource; + + if (getExportedResources_ != NULL) + { + resource = getExportedResources_->add_resources(); + } + else if (getLastExportedResource_ != NULL) + { + if (getLastExportedResource_->found()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } - OrthancPluginExportedResource exported; - exported.seq = seq; - exported.resourceType = resourceType; - exported.publicId = StoreString(publicId); - exported.modality = StoreString(modality); - exported.date = StoreString(date); - exported.patientId = StoreString(patientId); - exported.studyInstanceUid = StoreString(studyInstanceUid); - exported.seriesInstanceUid = StoreString(seriesInstanceUid); - exported.sopInstanceUid = StoreString(sopInstanceUid); - - exported_.push_back(exported); + getLastExportedResource_->set_found(true); + resource = getLastExportedResource_->mutable_resource(); + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + + resource->set_seq(seq); + resource->set_resource_type(Convert(resourceType)); + resource->set_public_id(publicId); + resource->set_modality(modality); + resource->set_date(date); + resource->set_patient_id(patientId); + resource->set_study_instance_uid(studyInstanceUid); + resource->set_series_instance_uid(seriesInstanceUid); + resource->set_sop_instance_uid(sopInstanceUid); } - virtual void AnswerMatchingResource(const std::string& resourceId) ORTHANC_OVERRIDE { - SetupAnswerType(_OrthancPluginDatabaseAnswerType_MatchingResource); - - OrthancPluginMatchingResource match; - match.resourceId = StoreString(resourceId); - match.someInstanceId = NULL; - - matches_.push_back(match); + if (lookupResources_ != NULL) + { + lookupResources_->add_resources_ids(resourceId); + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } } - virtual void AnswerMatchingResource(const std::string& resourceId, const std::string& someInstanceId) ORTHANC_OVERRIDE { - SetupAnswerType(_OrthancPluginDatabaseAnswerType_MatchingResource); - - OrthancPluginMatchingResource match; - match.resourceId = StoreString(resourceId); - match.someInstanceId = StoreString(someInstanceId); - - matches_.push_back(match); - } - - - void AnswerIntegers32(const std::list<int32_t>& values) - { - SetupAnswerType(_OrthancPluginDatabaseAnswerType_Int32); - CopyListToVector(integers32_, values); - } - - - void AnswerIntegers64(const std::list<int64_t>& values) - { - SetupAnswerType(_OrthancPluginDatabaseAnswerType_Int64); - CopyListToVector(integers64_, values); - } - - - void AnswerInteger64(int64_t value) - { - SetupAnswerType(_OrthancPluginDatabaseAnswerType_Int64); - - integers64_.resize(1); - integers64_[0] = value; - } - - - void AnswerMetadata(int32_t metadata, - const std::string& value) - { - SetupAnswerType(_OrthancPluginDatabaseAnswerType_Metadata); - - Metadata tmp; - tmp.metadata = metadata; - tmp.value = StoreString(value); - - metadata_.push_back(tmp); - } - - - void AnswerStrings(const std::list<std::string>& values) - { - SetupAnswerType(_OrthancPluginDatabaseAnswerType_String); - CopyListToVector(stringAnswers_, values); - } - - - void AnswerString(const std::string& value) - { - SetupAnswerType(_OrthancPluginDatabaseAnswerType_String); - - if (stringAnswers_.empty()) + if (lookupResources_ != NULL) { - stringAnswers_.push_back(value); + lookupResources_->add_resources_ids(resourceId); + lookupResources_->add_instances_ids(someInstanceId); } else { @@ -794,1312 +420,1054 @@ } } }; - - - IDatabaseBackendOutput* DatabaseBackendAdapterV4::Factory::CreateOutput() - { - return new DatabaseBackendAdapterV4::Output; - } - - - class DatabaseBackendAdapterV4::Transaction : public boost::noncopyable - { - private: - Adapter& adapter_; - std::unique_ptr<Adapter::DatabaseAccessor> accessor_; - std::unique_ptr<Output> output_; - - public: - Transaction(Adapter& adapter) : - adapter_(adapter), - accessor_(new Adapter::DatabaseAccessor(adapter)), - output_(new Output) - { - } + - ~Transaction() - { - } - - IndexBackend& GetBackend() const - { - return accessor_->GetBackend(); - } - - Output& GetOutput() const - { - return *output_; - } - - DatabaseManager& GetManager() const - { - return accessor_->GetManager(); - } - }; - - - static OrthancPluginErrorCode ReadAnswersCount(OrthancPluginDatabaseTransaction* transaction, - uint32_t* target /* out */) + static void ProcessDatabaseOperation(Orthanc::DatabasePluginMessages::DatabaseResponse& response, + const Orthanc::DatabasePluginMessages::DatabaseRequest& request, + IndexConnectionsPool& pool) { - assert(target != NULL); - const DatabaseBackendAdapterV4::Transaction& that = *reinterpret_cast<const DatabaseBackendAdapterV4::Transaction*>(transaction); - return that.GetOutput().ReadAnswersCount(*target); - } + switch (request.operation()) + { + case Orthanc::DatabasePluginMessages::OPERATION_GET_SYSTEM_INFORMATION: + { + IndexConnectionsPool::Accessor accessor(pool); + response.mutable_get_system_information()->set_database_version(accessor.GetBackend().GetDatabaseVersion(accessor.GetManager())); + response.mutable_get_system_information()->set_supports_flush_to_disk(false); + response.mutable_get_system_information()->set_supports_revisions(accessor.GetBackend().HasRevisionsSupport()); + response.mutable_get_system_information()->set_supports_labels(accessor.GetBackend().HasLabelsSupport()); +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 12, 3) + response.mutable_get_system_information()->set_supports_increment_global_property(accessor.GetBackend().HasAtomicIncrementGlobalProperty()); + response.mutable_get_system_information()->set_has_update_and_get_statistics(accessor.GetBackend().HasUpdateAndGetStatistics()); + response.mutable_get_system_information()->set_has_measure_latency(accessor.GetBackend().HasMeasureLatency()); +#endif + +#if ORTHANC_PLUGINS_HAS_INTEGRATED_FIND == 1 + response.mutable_get_system_information()->set_supports_find(accessor.GetBackend().HasFindSupport()); + response.mutable_get_system_information()->set_has_extended_changes(accessor.GetBackend().HasExtendedChanges()); +#endif + + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_OPEN: + { + std::list<IdentifierTag> identifierTags; - static OrthancPluginErrorCode ReadAnswerAttachment2(OrthancPluginDatabaseTransaction* transaction, - OrthancPluginAttachment2* target /* out */, - uint32_t index) - { - assert(target != NULL); - const DatabaseBackendAdapterV4::Transaction& that = *reinterpret_cast<const DatabaseBackendAdapterV4::Transaction*>(transaction); - return that.GetOutput().ReadAnswerAttachment2(*target, index); - } + if (request.open().identifier_tags().empty()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, + "No identifier tag was provided by the Orthanc core"); + } + for (int i = 0; i < request.open().identifier_tags().size(); i++) + { + const Orthanc::DatabasePluginMessages::Open_Request_IdentifierTag& tag = request.open().identifier_tags(i); + identifierTags.push_back(IdentifierTag(MessagesToolbox::Convert(tag.level()), + Orthanc::DicomTag(tag.group(), tag.element()), + tag.name())); + } + + pool.OpenConnections(true, identifierTags); + + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_CLOSE: + { + pool.CloseConnections(); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_FLUSH_TO_DISK: + { + // Raise an exception since "set_supports_flush_to_disk(false)" + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } - static OrthancPluginErrorCode ReadAnswerChange(OrthancPluginDatabaseTransaction* transaction, - OrthancPluginChange* target /* out */, - uint32_t index) - { - assert(target != NULL); - const DatabaseBackendAdapterV4::Transaction& that = *reinterpret_cast<const DatabaseBackendAdapterV4::Transaction*>(transaction); - return that.GetOutput().ReadAnswerChange(*target, index); - } + case Orthanc::DatabasePluginMessages::OPERATION_START_TRANSACTION: + { + std::unique_ptr<IndexConnectionsPool::Accessor> transaction(new IndexConnectionsPool::Accessor(pool)); + switch (request.start_transaction().type()) + { + case Orthanc::DatabasePluginMessages::TRANSACTION_READ_ONLY: + transaction->GetManager().StartTransaction(TransactionType_ReadOnly); + break; + + case Orthanc::DatabasePluginMessages::TRANSACTION_READ_WRITE: + transaction->GetManager().StartTransaction(TransactionType_ReadWrite); + break; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } - static OrthancPluginErrorCode ReadAnswerDicomTag(OrthancPluginDatabaseTransaction* transaction, - uint16_t* group, - uint16_t* element, - const char** value, - uint32_t index) - { - assert(group != NULL); - assert(element != NULL); - assert(value != NULL); - const DatabaseBackendAdapterV4::Transaction& that = *reinterpret_cast<const DatabaseBackendAdapterV4::Transaction*>(transaction); - return that.GetOutput().ReadAnswerDicomTag(*group, *element, *value, index); - } + response.mutable_start_transaction()->set_transaction(reinterpret_cast<intptr_t>(transaction.release())); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_UPGRADE: + { + IndexConnectionsPool::Accessor accessor(pool); + OrthancPluginStorageArea* storageArea = reinterpret_cast<OrthancPluginStorageArea*>(request.upgrade().storage_area()); + accessor.GetBackend().UpgradeDatabase(accessor.GetManager(), request.upgrade().target_version(), storageArea); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_FINALIZE_TRANSACTION: + { + IndexConnectionsPool::Accessor* transaction = reinterpret_cast<IndexConnectionsPool::Accessor*>(request.finalize_transaction().transaction()); + + if (transaction == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + } + else + { + delete transaction; + } + + break; + } +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 12, 3) + case Orthanc::DatabasePluginMessages::OPERATION_MEASURE_LATENCY: + { + IndexConnectionsPool::Accessor accessor(pool); + response.mutable_measure_latency()->set_latency_us(accessor.GetBackend().MeasureLatency(accessor.GetManager())); + break; + } +#endif - static OrthancPluginErrorCode ReadAnswerExportedResource(OrthancPluginDatabaseTransaction* transaction, - OrthancPluginExportedResource* target /* out */, - uint32_t index) - { - assert(target != NULL); - const DatabaseBackendAdapterV4::Transaction& that = *reinterpret_cast<const DatabaseBackendAdapterV4::Transaction*>(transaction); - return that.GetOutput().ReadAnswerExportedResource(*target, index); + default: + LOG(ERROR) << "Not implemented database operation from protobuf: " << request.operation(); + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } } - static OrthancPluginErrorCode ReadAnswerInt32(OrthancPluginDatabaseTransaction* transaction, - int32_t* target, - uint32_t index) - { - assert(target != NULL); - const DatabaseBackendAdapterV4::Transaction& that = *reinterpret_cast<const DatabaseBackendAdapterV4::Transaction*>(transaction); - return that.GetOutput().ReadAnswerInt32(*target, index); - } - - - static OrthancPluginErrorCode ReadAnswerInt64(OrthancPluginDatabaseTransaction* transaction, - int64_t* target, - uint32_t index) + static void ApplyLookupResources(Orthanc::DatabasePluginMessages::LookupResources_Response& response, + const Orthanc::DatabasePluginMessages::LookupResources_Request& request, + IndexBackend& backend, + DatabaseManager& manager) { - assert(target != NULL); - const DatabaseBackendAdapterV4::Transaction& that = *reinterpret_cast<const DatabaseBackendAdapterV4::Transaction*>(transaction); - return that.GetOutput().ReadAnswerInt64(*target, index); - } + size_t countValues = 0; + + for (int i = 0; i < request.lookup().size(); i++) + { + const Orthanc::DatabasePluginMessages::DatabaseConstraint& constraint = request.lookup(i); + countValues += constraint.values().size(); + } + + std::vector<const char*> values; + values.reserve(countValues); + + DatabaseConstraints lookup; + for (int i = 0; i < request.lookup().size(); i++) + { + const Orthanc::DatabasePluginMessages::DatabaseConstraint& constraint = request.lookup(i); + + if (constraint.tag_group() > 0xffffu || + constraint.tag_element() > 0xffffu) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + OrthancPluginDatabaseConstraint c; + c.level = Convert(constraint.level()); + c.tagGroup = constraint.tag_group(); + c.tagElement = constraint.tag_element(); + c.isIdentifierTag = (constraint.is_identifier_tag() ? 1 : 0); + c.isCaseSensitive = (constraint.is_case_sensitive() ? 1 : 0); + c.isMandatory = (constraint.is_mandatory() ? 1 : 0); - static OrthancPluginErrorCode ReadAnswerMatchingResource(OrthancPluginDatabaseTransaction* transaction, - OrthancPluginMatchingResource* target, - uint32_t index) - { - assert(target != NULL); - const DatabaseBackendAdapterV4::Transaction& that = *reinterpret_cast<const DatabaseBackendAdapterV4::Transaction*>(transaction); - return that.GetOutput().ReadAnswerMatchingResource(*target, index); + switch (constraint.type()) + { + case Orthanc::DatabasePluginMessages::CONSTRAINT_EQUAL: + c.type = OrthancPluginConstraintType_Equal; + break; + + case Orthanc::DatabasePluginMessages::CONSTRAINT_SMALLER_OR_EQUAL: + c.type = OrthancPluginConstraintType_SmallerOrEqual; + break; + + case Orthanc::DatabasePluginMessages::CONSTRAINT_GREATER_OR_EQUAL: + c.type = OrthancPluginConstraintType_GreaterOrEqual; + break; + + case Orthanc::DatabasePluginMessages::CONSTRAINT_WILDCARD: + c.type = OrthancPluginConstraintType_Wildcard; + break; + + case Orthanc::DatabasePluginMessages::CONSTRAINT_LIST: + c.type = OrthancPluginConstraintType_List; + break; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + c.valuesCount = constraint.values().size(); + + if (c.valuesCount == 0) + { + c.values = NULL; + } + else + { + c.values = &values[values.size()]; + + for (int j = 0; j < constraint.values().size(); j++) + { + assert(values.size() < countValues); + values.push_back(constraint.values(j).c_str()); + } + } + + lookup.AddConstraint(new DatabaseConstraint(c)); + } + + assert(values.size() == countValues); + + std::set<std::string> labels; + + for (int i = 0; i < request.labels().size(); i++) + { + labels.insert(request.labels(i)); + } + + LabelsConstraint labelsConstraint; + switch (request.labels_constraint()) + { + case Orthanc::DatabasePluginMessages::LABELS_CONSTRAINT_ALL: + labelsConstraint = LabelsConstraint_All; + break; + + case Orthanc::DatabasePluginMessages::LABELS_CONSTRAINT_ANY: + labelsConstraint = LabelsConstraint_Any; + break; + + case Orthanc::DatabasePluginMessages::LABELS_CONSTRAINT_NONE: + labelsConstraint = LabelsConstraint_None; + break; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + Output output(response); + backend.LookupResources(output, manager, lookup, Convert(request.query_level()), + labels, labelsConstraint, request.limit(), request.retrieve_instances_ids()); } - - static OrthancPluginErrorCode ReadAnswerMetadata(OrthancPluginDatabaseTransaction* transaction, - int32_t* metadata, - const char** value, - uint32_t index) + + static void ProcessTransactionOperation(Orthanc::DatabasePluginMessages::TransactionResponse& response, + const Orthanc::DatabasePluginMessages::TransactionRequest& request, + IndexBackend& backend, + DatabaseManager& manager) { - assert(metadata != NULL); - assert(value != NULL); - const DatabaseBackendAdapterV4::Transaction& that = *reinterpret_cast<const DatabaseBackendAdapterV4::Transaction*>(transaction); - return that.GetOutput().ReadAnswerMetadata(*metadata, *value, index); - } + switch (request.operation()) + { + case Orthanc::DatabasePluginMessages::OPERATION_ROLLBACK: + { + manager.RollbackTransaction(); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_COMMIT: + { + manager.CommitTransaction(); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_ADD_ATTACHMENT: + { + OrthancPluginAttachment attachment; + attachment.uuid = request.add_attachment().attachment().uuid().c_str(); + attachment.contentType = request.add_attachment().attachment().content_type(); + attachment.uncompressedSize = request.add_attachment().attachment().uncompressed_size(); + attachment.uncompressedHash = request.add_attachment().attachment().uncompressed_hash().c_str(); + attachment.compressionType = request.add_attachment().attachment().compression_type(); + attachment.compressedSize = request.add_attachment().attachment().compressed_size(); + attachment.compressedHash = request.add_attachment().attachment().compressed_hash().c_str(); + + backend.AddAttachment(manager, request.add_attachment().id(), attachment, request.add_attachment().revision()); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_CLEAR_CHANGES: + { + backend.ClearChanges(manager); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_CLEAR_EXPORTED_RESOURCES: + { + backend.ClearExportedResources(manager); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_DELETE_ATTACHMENT: + { + Output output(*response.mutable_delete_attachment()); + backend.DeleteAttachment(output, manager, request.delete_attachment().id(), request.delete_attachment().type()); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_DELETE_METADATA: + { + backend.DeleteMetadata(manager, request.delete_metadata().id(), request.delete_metadata().type()); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_DELETE_RESOURCE: + { + response.mutable_delete_resource()->set_is_remaining_ancestor(false); + + Output output(*response.mutable_delete_resource()); + backend.DeleteResource(output, manager, request.delete_resource().id()); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_GET_ALL_METADATA: + { + typedef std::map<int32_t, std::string> Values; + + Values values; + backend.GetAllMetadata(values, manager, request.get_all_metadata().id()); + + response.mutable_get_all_metadata()->mutable_metadata()->Reserve(values.size()); + for (Values::const_iterator it = values.begin(); it != values.end(); ++it) + { + Orthanc::DatabasePluginMessages::GetAllMetadata_Response_Metadata* metadata = + response.mutable_get_all_metadata()->add_metadata(); + metadata->set_type(it->first); + metadata->set_value(it->second); + } + + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_GET_ALL_PUBLIC_IDS: + { + std::list<std::string> values; + backend.GetAllPublicIds(values, manager, Convert(request.get_all_public_ids().resource_type())); + + response.mutable_get_all_public_ids()->mutable_ids()->Reserve(values.size()); + for (std::list<std::string>::const_iterator it = values.begin(); it != values.end(); ++it) + { + response.mutable_get_all_public_ids()->add_ids(*it); + } + + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_GET_ALL_PUBLIC_IDS_WITH_LIMITS: + { + std::list<std::string> values; + backend.GetAllPublicIds(values, manager, Convert(request.get_all_public_ids_with_limits().resource_type()), + request.get_all_public_ids_with_limits().since(), + request.get_all_public_ids_with_limits().limit()); + + response.mutable_get_all_public_ids_with_limits()->mutable_ids()->Reserve(values.size()); + for (std::list<std::string>::const_iterator it = values.begin(); it != values.end(); ++it) + { + response.mutable_get_all_public_ids_with_limits()->add_ids(*it); + } + + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_GET_CHANGES: + { + Output output(*response.mutable_get_changes()); + + bool done; + backend.GetChanges(output, done, manager, request.get_changes().since(), request.get_changes().limit()); + + response.mutable_get_changes()->set_done(done); + break; + } +#if ORTHANC_PLUGINS_HAS_CHANGES_EXTENDED == 1 + case Orthanc::DatabasePluginMessages::OPERATION_GET_CHANGES_EXTENDED: + { + Output output(*response.mutable_get_changes_extended()); + + bool done; + std::set<uint32_t> changeTypes; + for (int i = 0; i < request.get_changes_extended().change_type_size(); ++i) + { + changeTypes.insert(request.get_changes_extended().change_type(i)); + } + + backend.GetChangesExtended(output, done, manager, request.get_changes_extended().since(), request.get_changes_extended().to(), changeTypes, request.get_changes_extended().limit()); + + response.mutable_get_changes_extended()->set_done(done); + break; + } +#endif + + case Orthanc::DatabasePluginMessages::OPERATION_GET_CHILDREN_INTERNAL_ID: + { + std::list<int64_t> values; + backend.GetChildrenInternalId(values, manager, request.get_children_internal_id().id()); + + response.mutable_get_children_internal_id()->mutable_ids()->Reserve(values.size()); + for (std::list<int64_t>::const_iterator it = values.begin(); it != values.end(); ++it) + { + response.mutable_get_children_internal_id()->add_ids(*it); + } + + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_GET_CHILDREN_PUBLIC_ID: + { + std::list<std::string> values; + backend.GetChildrenPublicId(values, manager, request.get_children_public_id().id()); + response.mutable_get_children_public_id()->mutable_ids()->Reserve(values.size()); + for (std::list<std::string>::const_iterator it = values.begin(); it != values.end(); ++it) + { + response.mutable_get_children_public_id()->add_ids(*it); + } + + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_GET_EXPORTED_RESOURCES: + { + Output output(*response.mutable_get_exported_resources()); + + bool done; + backend.GetExportedResources(output, done, manager, request.get_exported_resources().since(), + request.get_exported_resources().limit()); + + response.mutable_get_exported_resources()->set_done(done); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_GET_LAST_CHANGE: + { + response.mutable_get_last_change()->set_found(false); + + Output output(*response.mutable_get_last_change()); + backend.GetLastChange(output, manager); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_GET_LAST_EXPORTED_RESOURCE: + { + response.mutable_get_last_exported_resource()->set_found(false); + + Output output(*response.mutable_get_last_exported_resource()); + backend.GetLastExportedResource(output, manager); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_GET_MAIN_DICOM_TAGS: + { + Output output(*response.mutable_get_main_dicom_tags()); + backend.GetMainDicomTags(output, manager, request.get_main_dicom_tags().id()); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_GET_PUBLIC_ID: + { + const std::string id = backend.GetPublicId(manager, request.get_public_id().id()); + response.mutable_get_public_id()->set_id(id); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_GET_RESOURCES_COUNT: + { + OrthancPluginResourceType type = Convert(request.get_resources_count().type()); + uint64_t count = backend.GetResourcesCount(manager, type); + response.mutable_get_resources_count()->set_count(count); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_GET_RESOURCE_TYPE: + { + OrthancPluginResourceType type = backend.GetResourceType(manager, request.get_resource_type().id()); + response.mutable_get_resource_type()->set_type(Convert(type)); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_GET_TOTAL_COMPRESSED_SIZE: + { + response.mutable_get_total_compressed_size()->set_size(backend.GetTotalCompressedSize(manager)); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_GET_TOTAL_UNCOMPRESSED_SIZE: + { + response.mutable_get_total_uncompressed_size()->set_size(backend.GetTotalUncompressedSize(manager)); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_IS_PROTECTED_PATIENT: + { + bool isProtected = backend.IsProtectedPatient(manager, request.is_protected_patient().patient_id()); + response.mutable_is_protected_patient()->set_protected_patient(isProtected); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_LIST_AVAILABLE_ATTACHMENTS: + { + std::list<int32_t> values; + backend.ListAvailableAttachments(values, manager, request.list_available_attachments().id()); + + response.mutable_list_available_attachments()->mutable_attachments()->Reserve(values.size()); + for (std::list<int32_t>::const_iterator it = values.begin(); it != values.end(); ++it) + { + response.mutable_list_available_attachments()->add_attachments(*it); + } + + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_LOG_CHANGE: + { + backend.LogChange(manager, request.log_change().change_type(), + request.log_change().resource_id(), + Convert(request.log_change().resource_type()), + request.log_change().date().c_str()); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_LOG_EXPORTED_RESOURCE: + { + backend.LogExportedResource(manager, + Convert(request.log_exported_resource().resource_type()), + request.log_exported_resource().public_id().c_str(), + request.log_exported_resource().modality().c_str(), + request.log_exported_resource().date().c_str(), + request.log_exported_resource().patient_id().c_str(), + request.log_exported_resource().study_instance_uid().c_str(), + request.log_exported_resource().series_instance_uid().c_str(), + request.log_exported_resource().sop_instance_uid().c_str()); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_LOOKUP_ATTACHMENT: + { + Output output(*response.mutable_lookup_attachment()); + + int64_t revision = -1; + backend.LookupAttachment(output, revision, manager, request.lookup_attachment().id(), request.lookup_attachment().content_type()); + + if (response.lookup_attachment().found()) + { + response.mutable_lookup_attachment()->set_revision(revision); + } + + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_LOOKUP_GLOBAL_PROPERTY: + { + std::string value; + if (backend.LookupGlobalProperty(value, manager, request.lookup_global_property().server_id().c_str(), + request.lookup_global_property().property())) + { + response.mutable_lookup_global_property()->set_found(true); + response.mutable_lookup_global_property()->set_value(value); + } + else + { + response.mutable_lookup_global_property()->set_found(false); + } + + break; + } + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 12, 3) + case Orthanc::DatabasePluginMessages::OPERATION_UPDATE_AND_GET_STATISTICS: + { + int64_t patientsCount, studiesCount, seriesCount, instancesCount, compressedSize, uncompressedSize; + backend.UpdateAndGetStatistics(manager, patientsCount, studiesCount, seriesCount, instancesCount, compressedSize, uncompressedSize); + + response.mutable_update_and_get_statistics()->set_patients_count(patientsCount); + response.mutable_update_and_get_statistics()->set_studies_count(studiesCount); + response.mutable_update_and_get_statistics()->set_series_count(seriesCount); + response.mutable_update_and_get_statistics()->set_instances_count(instancesCount); + response.mutable_update_and_get_statistics()->set_total_compressed_size(compressedSize); + response.mutable_update_and_get_statistics()->set_total_uncompressed_size(uncompressedSize); + break; + } +#endif - static OrthancPluginErrorCode ReadAnswerString(OrthancPluginDatabaseTransaction* transaction, - const char** target, - uint32_t index) - { - assert(target != NULL); - const DatabaseBackendAdapterV4::Transaction& that = *reinterpret_cast<const DatabaseBackendAdapterV4::Transaction*>(transaction); - return that.GetOutput().ReadAnswerString(*target, index); +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 12, 3) + case Orthanc::DatabasePluginMessages::OPERATION_INCREMENT_GLOBAL_PROPERTY: + { + int64_t value = backend.IncrementGlobalProperty(manager, request.increment_global_property().server_id().c_str(), + request.increment_global_property().property(), + request.increment_global_property().increment()); + response.mutable_increment_global_property()->set_new_value(value); + break; + } +#endif + + case Orthanc::DatabasePluginMessages::OPERATION_LOOKUP_METADATA: + { + std::string value; + int64_t revision = -1; + if (backend.LookupMetadata(value, revision, manager, request.lookup_metadata().id(), request.lookup_metadata().metadata_type())) + { + response.mutable_lookup_metadata()->set_found(true); + response.mutable_lookup_metadata()->set_value(value); + response.mutable_lookup_metadata()->set_revision(revision); + } + else + { + response.mutable_lookup_metadata()->set_found(false); + } + + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_LOOKUP_PARENT: + { + int64_t parent = -1; + if (backend.LookupParent(parent, manager, request.lookup_parent().id())) + { + response.mutable_lookup_parent()->set_found(true); + response.mutable_lookup_parent()->set_parent(parent); + } + else + { + response.mutable_lookup_parent()->set_found(false); + } + + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_LOOKUP_RESOURCE: + { + int64_t internalId = -1; + OrthancPluginResourceType type; + if (backend.LookupResource(internalId, type, manager, request.lookup_resource().public_id().c_str())) + { + response.mutable_lookup_resource()->set_found(true); + response.mutable_lookup_resource()->set_internal_id(internalId); + response.mutable_lookup_resource()->set_type(Convert(type)); + } + else + { + response.mutable_lookup_resource()->set_found(false); + } + + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_SELECT_PATIENT_TO_RECYCLE: + { + int64_t patientId = -1; + if (backend.SelectPatientToRecycle(patientId, manager)) + { + response.mutable_select_patient_to_recycle()->set_found(true); + response.mutable_select_patient_to_recycle()->set_patient_id(patientId); + } + else + { + response.mutable_select_patient_to_recycle()->set_found(false); + } + + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_SELECT_PATIENT_TO_RECYCLE_WITH_AVOID: + { + int64_t patientId = -1; + if (backend.SelectPatientToRecycle(patientId, manager, request.select_patient_to_recycle_with_avoid().patient_id_to_avoid())) + { + response.mutable_select_patient_to_recycle_with_avoid()->set_found(true); + response.mutable_select_patient_to_recycle_with_avoid()->set_patient_id(patientId); + } + else + { + response.mutable_select_patient_to_recycle_with_avoid()->set_found(false); + } + + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_SET_GLOBAL_PROPERTY: + { + backend.SetGlobalProperty(manager, request.set_global_property().server_id().c_str(), + request.set_global_property().property(), + request.set_global_property().value().c_str()); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_CLEAR_MAIN_DICOM_TAGS: + { + backend.ClearMainDicomTags(manager, request.clear_main_dicom_tags().id()); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_SET_METADATA: + { + backend.SetMetadata(manager, request.set_metadata().id(), + request.set_metadata().metadata_type(), + request.set_metadata().value().c_str(), + request.set_metadata().revision()); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_SET_PROTECTED_PATIENT: + { + backend.SetProtectedPatient(manager, request.set_protected_patient().patient_id(), + request.set_protected_patient().protected_patient()); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_IS_DISK_SIZE_ABOVE: + { + bool above = (backend.GetTotalCompressedSize(manager) >= request.is_disk_size_above().threshold()); + response.mutable_is_disk_size_above()->set_result(above); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_LOOKUP_RESOURCES: + { + ApplyLookupResources(*response.mutable_lookup_resources(), request.lookup_resources(), backend, manager); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_CREATE_INSTANCE: + { + const char* hashPatient = request.create_instance().patient().c_str(); + const char* hashStudy = request.create_instance().study().c_str(); + const char* hashSeries = request.create_instance().series().c_str(); + const char* hashInstance = request.create_instance().instance().c_str(); + + OrthancPluginCreateInstanceResult result; + + if (backend.HasCreateInstance()) + { + backend.CreateInstance(result, manager, hashPatient, hashStudy, hashSeries, hashInstance); + } + else + { + backend.CreateInstanceGeneric(result, manager, hashPatient, hashStudy, hashSeries, hashInstance); + } + + response.mutable_create_instance()->set_is_new_instance(result.isNewInstance); + response.mutable_create_instance()->set_instance_id(result.instanceId); + + if (result.isNewInstance) + { + response.mutable_create_instance()->set_is_new_patient(result.isNewPatient); + response.mutable_create_instance()->set_is_new_study(result.isNewStudy); + response.mutable_create_instance()->set_is_new_series(result.isNewSeries); + response.mutable_create_instance()->set_patient_id(result.patientId); + response.mutable_create_instance()->set_study_id(result.studyId); + response.mutable_create_instance()->set_series_id(result.seriesId); + } + + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_SET_RESOURCES_CONTENT: + { + std::vector<OrthancPluginResourcesContentTags> identifierTags; + std::vector<OrthancPluginResourcesContentTags> mainDicomTags; + + identifierTags.reserve(request.set_resources_content().tags().size()); + mainDicomTags.reserve(request.set_resources_content().tags().size()); + + for (int i = 0; i < request.set_resources_content().tags().size(); i++) + { + if (request.set_resources_content().tags(i).group() > 0xffffu || + request.set_resources_content().tags(i).element() > 0xffffu) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + OrthancPluginResourcesContentTags tag; + tag.resource = request.set_resources_content().tags(i).resource_id(); + tag.group = request.set_resources_content().tags(i).group(); + tag.element = request.set_resources_content().tags(i).element(); + tag.value = request.set_resources_content().tags(i).value().c_str(); + + if (request.set_resources_content().tags(i).is_identifier()) + { + identifierTags.push_back(tag); + } + else + { + mainDicomTags.push_back(tag); + } + } + + std::vector<OrthancPluginResourcesContentMetadata> metadata; + metadata.reserve(request.set_resources_content().metadata().size()); + + for (int i = 0; i < request.set_resources_content().metadata().size(); i++) + { + OrthancPluginResourcesContentMetadata item; + item.resource = request.set_resources_content().metadata(i).resource_id(); + item.metadata = request.set_resources_content().metadata(i).metadata(); + item.value = request.set_resources_content().metadata(i).value().c_str(); + metadata.push_back(item); + } + + backend.SetResourcesContent(manager, + identifierTags.size(), (identifierTags.empty() ? NULL : &identifierTags[0]), + mainDicomTags.size(), (mainDicomTags.empty() ? NULL : &mainDicomTags[0]), + metadata.size(), (metadata.empty() ? NULL : &metadata[0])); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_GET_CHILDREN_METADATA: + { + std::list<std::string> values; + backend.GetChildrenMetadata(values, manager, request.get_children_metadata().id(), request.get_children_metadata().metadata()); + + response.mutable_get_children_metadata()->mutable_values()->Reserve(values.size()); + for (std::list<std::string>::const_iterator it = values.begin(); it != values.end(); ++it) + { + response.mutable_get_children_metadata()->add_values(*it); + } + + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_GET_LAST_CHANGE_INDEX: + { + response.mutable_get_last_change_index()->set_result(backend.GetLastChangeIndex(manager)); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_LOOKUP_RESOURCE_AND_PARENT: + { + int64_t id; + OrthancPluginResourceType type; + std::string parent; + + if (backend.LookupResourceAndParent(id, type, parent, manager, request.lookup_resource_and_parent().public_id().c_str())) + { + response.mutable_lookup_resource_and_parent()->set_found(true); + response.mutable_lookup_resource_and_parent()->set_id(id); + response.mutable_lookup_resource_and_parent()->set_type(Convert(type)); + + switch (type) + { + case OrthancPluginResourceType_Study: + case OrthancPluginResourceType_Series: + case OrthancPluginResourceType_Instance: + if (parent.empty()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + else + { + response.mutable_lookup_resource_and_parent()->set_parent_public_id(parent); + } + break; + + case OrthancPluginResourceType_Patient: + if (!parent.empty()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + break; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + } + else + { + response.mutable_lookup_resource_and_parent()->set_found(false); + } + + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_ADD_LABEL: + { + backend.AddLabel(manager, request.add_label().id(), request.add_label().label()); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_REMOVE_LABEL: + { + backend.RemoveLabel(manager, request.remove_label().id(), request.remove_label().label()); + break; + } + + case Orthanc::DatabasePluginMessages::OPERATION_LIST_LABELS: + { + std::list<std::string> labels; + + if (request.list_labels().single_resource()) + { + backend.ListLabels(labels, manager, request.list_labels().id()); + } + else + { + backend.ListAllLabels(labels, manager); + } + + response.mutable_list_available_attachments()->mutable_attachments()->Reserve(labels.size()); + for (std::list<std::string>::const_iterator it = labels.begin(); it != labels.end(); ++it) + { + response.mutable_list_labels()->add_labels(*it); + } + + break; + } + +#if ORTHANC_PLUGINS_HAS_INTEGRATED_FIND == 1 + case Orthanc::DatabasePluginMessages::OPERATION_FIND: + { + backend.ExecuteFind(response, manager, request.find()); + break; + } +#endif + + default: + LOG(ERROR) << "Not implemented transaction operation from protobuf: " << request.operation(); + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } } - - static OrthancPluginErrorCode ReadEventsCount(OrthancPluginDatabaseTransaction* transaction, - uint32_t* target /* out */) + + static OrthancPluginErrorCode CallBackend(OrthancPluginMemoryBuffer64* serializedResponse, + void* rawPool, + const void* requestData, + uint64_t requestSize) { - assert(target != NULL); - const DatabaseBackendAdapterV4::Transaction& that = *reinterpret_cast<const DatabaseBackendAdapterV4::Transaction*>(transaction); - return that.GetOutput().ReadEventsCount(*target); - } + Orthanc::DatabasePluginMessages::Request request; + if (!request.ParseFromArray(requestData, requestSize)) + { + LOG(ERROR) << "Cannot parse message from the Orthanc core using protobuf"; + return OrthancPluginErrorCode_InternalError; + } - - static OrthancPluginErrorCode ReadEvent2(OrthancPluginDatabaseTransaction* transaction, - OrthancPluginDatabaseEvent2* event /* out */, - uint32_t index) - { - assert(event != NULL); - const DatabaseBackendAdapterV4::Transaction& that = *reinterpret_cast<const DatabaseBackendAdapterV4::Transaction*>(transaction); - return that.GetOutput().ReadEvent2(*event, index); - } + if (rawPool == NULL) + { + LOG(ERROR) << "Received a NULL pointer from the database"; + return OrthancPluginErrorCode_InternalError; + } - - static OrthancPluginErrorCode Open(void* database) - { - DatabaseBackendAdapterV4::Adapter* adapter = reinterpret_cast<DatabaseBackendAdapterV4::Adapter*>(database); + IndexConnectionsPool& pool = *reinterpret_cast<IndexConnectionsPool*>(rawPool); try { - adapter->OpenConnections(); + Orthanc::DatabasePluginMessages::Response response; + + switch (request.type()) + { + case Orthanc::DatabasePluginMessages::REQUEST_DATABASE: + ProcessDatabaseOperation(*response.mutable_database_response(), request.database_request(), pool); + break; + + case Orthanc::DatabasePluginMessages::REQUEST_TRANSACTION: + { + IndexConnectionsPool::Accessor& transaction = *reinterpret_cast<IndexConnectionsPool::Accessor*>(request.transaction_request().transaction()); + ProcessTransactionOperation(*response.mutable_transaction_response(), request.transaction_request(), + transaction.GetBackend(), transaction.GetManager()); + break; + } + + default: + LOG(ERROR) << "Not implemented request type from protobuf: " << request.type(); + break; + } + + std::string s; + if (!response.SerializeToString(&s)) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "Cannot serialize to protobuf"); + } + + if (OrthancPluginCreateMemoryBuffer64(pool.GetContext(), serializedResponse, s.size()) != OrthancPluginErrorCode_Success) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotEnoughMemory, "Cannot allocate a memory buffer"); + } + + if (!s.empty()) + { + assert(serializedResponse->size == s.size()); + memcpy(serializedResponse->data, s.c_str(), s.size()); + } + return OrthancPluginErrorCode_Success; } - ORTHANC_PLUGINS_DATABASE_CATCH(adapter->GetContext()); + catch (::Orthanc::OrthancException& e) + { + if (e.GetErrorCode() == ::Orthanc::ErrorCode_DatabaseCannotSerialize) + { + LOG(WARNING) << "An SQL transaction failed and will likely be retried: " << e.GetDetails(); + } + else + { + LOG(ERROR) << "Exception in database back-end: " << e.What(); + } + return static_cast<OrthancPluginErrorCode>(e.GetErrorCode()); + } + catch (::std::runtime_error& e) + { + LOG(ERROR) << "Exception in database back-end: " << e.what(); + return OrthancPluginErrorCode_DatabasePlugin; + } + catch (...) + { + LOG(ERROR) << "Native exception"; + return OrthancPluginErrorCode_DatabasePlugin; + } } - - static OrthancPluginErrorCode Close(void* database) + static void FinalizeBackend(void* rawPool) { - DatabaseBackendAdapterV4::Adapter* adapter = reinterpret_cast<DatabaseBackendAdapterV4::Adapter*>(database); - - try + if (rawPool != NULL) { - adapter->CloseConnections(); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(adapter->GetContext()); - } - - - static OrthancPluginErrorCode DestructDatabase(void* database) - { - DatabaseBackendAdapterV4::Adapter* adapter = reinterpret_cast<DatabaseBackendAdapterV4::Adapter*>(database); - - if (adapter == NULL) - { - return OrthancPluginErrorCode_InternalError; - } - else - { + IndexConnectionsPool* pool = reinterpret_cast<IndexConnectionsPool*>(rawPool); + if (isBackendInUse_) { isBackendInUse_ = false; } else { - OrthancPluginLogError(adapter->GetContext(), "More than one index backend was registered, internal error"); + LOG(ERROR) << "More than one index backend was registered, internal error"; } - - delete adapter; - - return OrthancPluginErrorCode_Success; - } - } - - - static OrthancPluginErrorCode GetDatabaseVersion(void* database, - uint32_t* version) - { - DatabaseBackendAdapterV4::Adapter* adapter = reinterpret_cast<DatabaseBackendAdapterV4::Adapter*>(database); - - try - { - DatabaseBackendAdapterV4::Adapter::DatabaseAccessor accessor(*adapter); - *version = accessor.GetBackend().GetDatabaseVersion(accessor.GetManager()); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(adapter->GetContext()); - } - - - static OrthancPluginErrorCode UpgradeDatabase(void* database, - OrthancPluginStorageArea* storageArea, - uint32_t targetVersion) - { - DatabaseBackendAdapterV4::Adapter* adapter = reinterpret_cast<DatabaseBackendAdapterV4::Adapter*>(database); - - try - { - DatabaseBackendAdapterV4::Adapter::DatabaseAccessor accessor(*adapter); - accessor.GetBackend().UpgradeDatabase(accessor.GetManager(), targetVersion, storageArea); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(adapter->GetContext()); - } - - static OrthancPluginErrorCode HasRevisionsSupport(void* database, - uint8_t* target) - { - DatabaseBackendAdapterV4::Adapter* adapter = reinterpret_cast<DatabaseBackendAdapterV4::Adapter*>(database); - - try - { - DatabaseBackendAdapterV4::Adapter::DatabaseAccessor accessor(*adapter); - *target = (accessor.GetBackend().HasRevisionsSupport() ? 1 : 0); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(adapter->GetContext()); - } - - - static OrthancPluginErrorCode HasAttachmentCustomDataSupport(void* database, - uint8_t* target) - { - DatabaseBackendAdapterV4::Adapter* adapter = reinterpret_cast<DatabaseBackendAdapterV4::Adapter*>(database); - - try - { - DatabaseBackendAdapterV4::Adapter::DatabaseAccessor accessor(*adapter); - *target = (accessor.GetBackend().HasAttachmentCustomDataSupport() ? 1 : 0); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(adapter->GetContext()); - } - - static OrthancPluginErrorCode StartTransaction(void* database, - OrthancPluginDatabaseTransaction** target /* out */, - OrthancPluginDatabaseTransactionType type) - { - DatabaseBackendAdapterV4::Adapter* adapter = reinterpret_cast<DatabaseBackendAdapterV4::Adapter*>(database); - - try - { - std::unique_ptr<DatabaseBackendAdapterV4::Transaction> transaction(new DatabaseBackendAdapterV4::Transaction(*adapter)); - - switch (type) - { - case OrthancPluginDatabaseTransactionType_ReadOnly: - transaction->GetManager().StartTransaction(TransactionType_ReadOnly); - break; - - case OrthancPluginDatabaseTransactionType_ReadWrite: - transaction->GetManager().StartTransaction(TransactionType_ReadWrite); - break; - - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - - *target = reinterpret_cast<OrthancPluginDatabaseTransaction*>(transaction.release()); - - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(adapter->GetContext()); - } - - - static OrthancPluginErrorCode DestructTransaction(OrthancPluginDatabaseTransaction* transaction) - { - if (transaction == NULL) - { - return OrthancPluginErrorCode_NullPointer; + delete pool; } else { - delete reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - return OrthancPluginErrorCode_Success; + LOG(ERROR) << "Received a null pointer from the Orthanc core, internal error"; } } - static OrthancPluginErrorCode Rollback(OrthancPluginDatabaseTransaction* transaction) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - t->GetManager().RollbackTransaction(); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode Commit(OrthancPluginDatabaseTransaction* transaction, - int64_t fileSizeDelta /* TODO - not used? */) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - t->GetManager().CommitTransaction(); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode AddAttachment2(OrthancPluginDatabaseTransaction* transaction, - int64_t id, - const OrthancPluginAttachment2* attachment, - int64_t revision) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - t->GetBackend().AddAttachment2(t->GetManager(), id, *attachment, revision); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode ClearChanges(OrthancPluginDatabaseTransaction* transaction) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - t->GetBackend().ClearChanges(t->GetManager()); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode ClearExportedResources(OrthancPluginDatabaseTransaction* transaction) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - t->GetBackend().ClearExportedResources(t->GetManager()); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode ClearMainDicomTags(OrthancPluginDatabaseTransaction* transaction, - int64_t resourceId) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - t->GetBackend().ClearMainDicomTags(t->GetManager(), resourceId); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode CreateInstance(OrthancPluginDatabaseTransaction* transaction, - OrthancPluginCreateInstanceResult* target /* out */, - const char* hashPatient, - const char* hashStudy, - const char* hashSeries, - const char* hashInstance) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - - if (t->GetBackend().HasCreateInstance()) - { - t->GetBackend().CreateInstance(*target, t->GetManager(), hashPatient, hashStudy, hashSeries, hashInstance); - } - else - { - t->GetBackend().CreateInstanceGeneric(*target, t->GetManager(), hashPatient, hashStudy, hashSeries, hashInstance); - } - - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode DeleteAttachment(OrthancPluginDatabaseTransaction* transaction, - int64_t id, - int32_t contentType) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - t->GetBackend().DeleteAttachment(t->GetOutput(), t->GetManager(), id, contentType); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode DeleteMetadata(OrthancPluginDatabaseTransaction* transaction, - int64_t id, - int32_t metadataType) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - t->GetBackend().DeleteMetadata(t->GetManager(), id, metadataType); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode DeleteResource(OrthancPluginDatabaseTransaction* transaction, - int64_t id) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - t->GetBackend().DeleteResource(t->GetOutput(), t->GetManager(), id); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode GetAllMetadata(OrthancPluginDatabaseTransaction* transaction, - int64_t id) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - - std::map<int32_t, std::string> values; - t->GetBackend().GetAllMetadata(values, t->GetManager(), id); - - for (std::map<int32_t, std::string>::const_iterator it = values.begin(); it != values.end(); ++it) - { - t->GetOutput().AnswerMetadata(it->first, it->second); - } - - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode GetAllPublicIds(OrthancPluginDatabaseTransaction* transaction, - OrthancPluginResourceType resourceType) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - - std::list<std::string> values; - t->GetBackend().GetAllPublicIds(values, t->GetManager(), resourceType); - t->GetOutput().AnswerStrings(values); - - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode GetAllPublicIdsWithLimit(OrthancPluginDatabaseTransaction* transaction, - OrthancPluginResourceType resourceType, - uint64_t since, - uint64_t limit) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - - std::list<std::string> values; - t->GetBackend().GetAllPublicIds(values, t->GetManager(), resourceType, since, limit); - t->GetOutput().AnswerStrings(values); - - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode GetChanges(OrthancPluginDatabaseTransaction* transaction, - uint8_t* targetDone /* out */, - int64_t since, - uint32_t maxResults) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - - bool done; - t->GetBackend().GetChanges(t->GetOutput(), done, t->GetManager(), since, maxResults); - *targetDone = (done ? 1 : 0); - - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode GetChildrenInternalId(OrthancPluginDatabaseTransaction* transaction, - int64_t id) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - - std::list<int64_t> values; - t->GetBackend().GetChildrenInternalId(values, t->GetManager(), id); - t->GetOutput().AnswerIntegers64(values); - - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode GetChildrenMetadata(OrthancPluginDatabaseTransaction* transaction, - int64_t resourceId, - int32_t metadata) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - - std::list<std::string> values; - t->GetBackend().GetChildrenMetadata(values, t->GetManager(), resourceId, metadata); - t->GetOutput().AnswerStrings(values); - - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode GetChildrenPublicId(OrthancPluginDatabaseTransaction* transaction, - int64_t id) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - - std::list<std::string> values; - t->GetBackend().GetChildrenPublicId(values, t->GetManager(), id); - t->GetOutput().AnswerStrings(values); - - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode GetExportedResources(OrthancPluginDatabaseTransaction* transaction, - uint8_t* targetDone /* out */, - int64_t since, - uint32_t maxResults) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - - bool done; - t->GetBackend().GetExportedResources(t->GetOutput(), done, t->GetManager(), since, maxResults); - *targetDone = (done ? 1 : 0); - - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode GetLastChange(OrthancPluginDatabaseTransaction* transaction) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - t->GetBackend().GetLastChange(t->GetOutput(), t->GetManager()); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode GetLastChangeIndex(OrthancPluginDatabaseTransaction* transaction, - int64_t* target) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - *target = t->GetBackend().GetLastChangeIndex(t->GetManager()); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode GetLastExportedResource(OrthancPluginDatabaseTransaction* transaction) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - t->GetBackend().GetLastExportedResource(t->GetOutput(), t->GetManager()); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode GetMainDicomTags(OrthancPluginDatabaseTransaction* transaction, - int64_t id) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - t->GetBackend().GetMainDicomTags(t->GetOutput(), t->GetManager(), id); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode GetPublicId(OrthancPluginDatabaseTransaction* transaction, - int64_t id) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - t->GetOutput().AnswerString(t->GetBackend().GetPublicId(t->GetManager(), id)); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode GetResourcesCount(OrthancPluginDatabaseTransaction* transaction, - uint64_t* target /* out */, - OrthancPluginResourceType resourceType) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - *target = t->GetBackend().GetResourcesCount(t->GetManager(), resourceType); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode GetResourceType(OrthancPluginDatabaseTransaction* transaction, - OrthancPluginResourceType* target /* out */, - uint64_t resourceId) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - *target = t->GetBackend().GetResourceType(t->GetManager(), resourceId); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode GetTotalCompressedSize(OrthancPluginDatabaseTransaction* transaction, - uint64_t* target /* out */) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - *target = t->GetBackend().GetTotalCompressedSize(t->GetManager()); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode GetTotalUncompressedSize(OrthancPluginDatabaseTransaction* transaction, - uint64_t* target /* out */) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - *target = t->GetBackend().GetTotalUncompressedSize(t->GetManager()); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode IsDiskSizeAbove(OrthancPluginDatabaseTransaction* transaction, - uint8_t* target, - uint64_t threshold) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - bool above = (t->GetBackend().GetTotalCompressedSize(t->GetManager()) >= threshold); - *target = (above ? 1 : 0); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode IsExistingResource(OrthancPluginDatabaseTransaction* transaction, - uint8_t* target, - int64_t resourceId) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - bool exists = t->GetBackend().IsExistingResource(t->GetManager(), resourceId); - *target = (exists ? 1 : 0); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode IsProtectedPatient(OrthancPluginDatabaseTransaction* transaction, - uint8_t* target, - int64_t resourceId) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - bool isProtected = t->GetBackend().IsProtectedPatient(t->GetManager(), resourceId); - *target = (isProtected ? 1 : 0); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode ListAvailableAttachments(OrthancPluginDatabaseTransaction* transaction, - int64_t resourceId) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - - std::list<int32_t> values; - t->GetBackend().ListAvailableAttachments(values, t->GetManager(), resourceId); - t->GetOutput().AnswerIntegers32(values); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode LogChange(OrthancPluginDatabaseTransaction* transaction, - int32_t changeType, - int64_t resourceId, - OrthancPluginResourceType resourceType, - const char* date) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - t->GetBackend().LogChange(t->GetManager(), changeType, resourceId, resourceType, date); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode LogExportedResource(OrthancPluginDatabaseTransaction* transaction, - OrthancPluginResourceType resourceType, - const char* publicId, - const char* modality, - const char* date, - const char* patientId, - const char* studyInstanceUid, - const char* seriesInstanceUid, - const char* sopInstanceUid) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - OrthancPluginExportedResource exported; - exported.seq = 0; - exported.resourceType = resourceType; - exported.publicId = publicId; - exported.modality = modality; - exported.date = date; - exported.patientId = patientId; - exported.studyInstanceUid = studyInstanceUid; - exported.seriesInstanceUid = seriesInstanceUid; - exported.sopInstanceUid = sopInstanceUid; - - t->GetOutput().Clear(); - t->GetBackend().LogExportedResource(t->GetManager(), exported); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode LookupAttachment(OrthancPluginDatabaseTransaction* transaction, - int64_t* revision /* out */, - int64_t resourceId, - int32_t contentType) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - t->GetBackend().LookupAttachment(t->GetOutput(), *revision, t->GetManager(), resourceId, contentType); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode LookupGlobalProperty(OrthancPluginDatabaseTransaction* transaction, - const char* serverIdentifier, - int32_t property) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - - std::string s; - if (t->GetBackend().LookupGlobalProperty(s, t->GetManager(), serverIdentifier, property)) - { - t->GetOutput().AnswerString(s); - } - - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode LookupMetadata(OrthancPluginDatabaseTransaction* transaction, - int64_t* revision /* out */, - int64_t id, - int32_t metadata) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - - std::string s; - if (t->GetBackend().LookupMetadata(s, *revision, t->GetManager(), id, metadata)) - { - t->GetOutput().AnswerString(s); - } - - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode LookupParent(OrthancPluginDatabaseTransaction* transaction, - uint8_t* existing /* out */, - int64_t* parentId /* out */, - int64_t id) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - - if (t->GetBackend().LookupParent(*parentId, t->GetManager(), id)) - { - *existing = 1; - } - else - { - *existing = 0; - } - - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode LookupResource(OrthancPluginDatabaseTransaction* transaction, - uint8_t* isExisting /* out */, - int64_t* id /* out */, - OrthancPluginResourceType* type /* out */, - const char* publicId) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - - if (t->GetBackend().LookupResource(*id, *type, t->GetManager(), publicId)) - { - *isExisting = 1; - } - else - { - *isExisting = 0; - } - - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode LookupResources(OrthancPluginDatabaseTransaction* transaction, - uint32_t constraintsCount, - const OrthancPluginDatabaseConstraint* constraints, - OrthancPluginResourceType queryLevel, - uint32_t limit, - uint8_t requestSomeInstanceId) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - - std::vector<Orthanc::DatabaseConstraint> lookup; - lookup.reserve(constraintsCount); - - for (uint32_t i = 0; i < constraintsCount; i++) - { - lookup.push_back(Orthanc::DatabaseConstraint(constraints[i])); - } - - t->GetBackend().LookupResources(t->GetOutput(), t->GetManager(), lookup, queryLevel, limit, (requestSomeInstanceId != 0)); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode LookupResourceAndParent(OrthancPluginDatabaseTransaction* transaction, - uint8_t* isExisting /* out */, - int64_t* id /* out */, - OrthancPluginResourceType* type /* out */, - const char* publicId) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - - std::string parent; - if (t->GetBackend().LookupResourceAndParent(*id, *type, parent, t->GetManager(), publicId)) - { - *isExisting = 1; - - if (!parent.empty()) - { - t->GetOutput().AnswerString(parent); - } - } - else - { - *isExisting = 0; - } - - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode SelectPatientToRecycle(OrthancPluginDatabaseTransaction* transaction, - uint8_t* patientAvailable, - int64_t* patientId) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - - if (t->GetBackend().SelectPatientToRecycle(*patientId, t->GetManager())) - { - *patientAvailable = 1; - } - else - { - *patientAvailable = 0; - } - - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode SelectPatientToRecycle2(OrthancPluginDatabaseTransaction* transaction, - uint8_t* patientAvailable, - int64_t* patientId, - int64_t patientIdToAvoid) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - - if (t->GetBackend().SelectPatientToRecycle(*patientId, t->GetManager(), patientIdToAvoid)) - { - *patientAvailable = 1; - } - else - { - *patientAvailable = 0; - } - - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode SetGlobalProperty(OrthancPluginDatabaseTransaction* transaction, - const char* serverIdentifier, - int32_t property, - const char* value) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - t->GetBackend().SetGlobalProperty(t->GetManager(), serverIdentifier, property, value); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode SetMetadata(OrthancPluginDatabaseTransaction* transaction, - int64_t id, - int32_t metadata, - const char* value, - int64_t revision) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - t->GetBackend().SetMetadata(t->GetManager(), id, metadata, value, revision); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode SetProtectedPatient(OrthancPluginDatabaseTransaction* transaction, - int64_t id, - uint8_t isProtected) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - t->GetBackend().SetProtectedPatient(t->GetManager(), id, (isProtected != 0)); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - - static OrthancPluginErrorCode SetResourcesContent(OrthancPluginDatabaseTransaction* transaction, - uint32_t countIdentifierTags, - const OrthancPluginResourcesContentTags* identifierTags, - uint32_t countMainDicomTags, - const OrthancPluginResourcesContentTags* mainDicomTags, - uint32_t countMetadata, - const OrthancPluginResourcesContentMetadata* metadata) - { - DatabaseBackendAdapterV4::Transaction* t = reinterpret_cast<DatabaseBackendAdapterV4::Transaction*>(transaction); - - try - { - t->GetOutput().Clear(); - t->GetBackend().SetResourcesContent(t->GetManager(), countIdentifierTags, identifierTags, - countMainDicomTags, mainDicomTags, countMetadata, metadata); - return OrthancPluginErrorCode_Success; - } - ORTHANC_PLUGINS_DATABASE_CATCH(t->GetBackend().GetContext()); - } - - void DatabaseBackendAdapterV4::Register(IndexBackend* backend, size_t countConnections, unsigned int maxDatabaseRetries) { + std::unique_ptr<IndexConnectionsPool> pool(new IndexConnectionsPool(backend, countConnections)); + if (isBackendInUse_) { throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); } - - if (backend == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); - } - - OrthancPluginDatabaseBackendV4 params; - memset(¶ms, 0, sizeof(params)); - - params.readAnswersCount = ReadAnswersCount; - params.readAnswerAttachment2 = ReadAnswerAttachment2; - params.readAnswerChange = ReadAnswerChange; - params.readAnswerDicomTag = ReadAnswerDicomTag; - params.readAnswerExportedResource = ReadAnswerExportedResource; - params.readAnswerInt32 = ReadAnswerInt32; - params.readAnswerInt64 = ReadAnswerInt64; - params.readAnswerMatchingResource = ReadAnswerMatchingResource; - params.readAnswerMetadata = ReadAnswerMetadata; - params.readAnswerString = ReadAnswerString; - - params.readEventsCount = ReadEventsCount; - params.readEvent2 = ReadEvent2; - - params.open = Open; - params.close = Close; - params.destructDatabase = DestructDatabase; - params.getDatabaseVersion = GetDatabaseVersion; - params.upgradeDatabase = UpgradeDatabase; - params.hasRevisionsSupport = HasRevisionsSupport; - params.hasAttachmentCustomDataSupport = HasAttachmentCustomDataSupport; - params.startTransaction = StartTransaction; - params.destructTransaction = DestructTransaction; - params.rollback = Rollback; - params.commit = Commit; - - params.addAttachment2 = AddAttachment2; - params.clearChanges = ClearChanges; - params.clearExportedResources = ClearExportedResources; - params.clearMainDicomTags = ClearMainDicomTags; - params.createInstance = CreateInstance; - params.deleteAttachment = DeleteAttachment; - params.deleteMetadata = DeleteMetadata; - params.deleteResource = DeleteResource; - params.getAllMetadata = GetAllMetadata; - params.getAllPublicIds = GetAllPublicIds; - params.getAllPublicIdsWithLimit = GetAllPublicIdsWithLimit; - params.getChanges = GetChanges; - params.getChildrenInternalId = GetChildrenInternalId; - params.getChildrenMetadata = GetChildrenMetadata; - params.getChildrenPublicId = GetChildrenPublicId; - params.getExportedResources = GetExportedResources; - params.getLastChange = GetLastChange; - params.getLastChangeIndex = GetLastChangeIndex; - params.getLastExportedResource = GetLastExportedResource; - params.getMainDicomTags = GetMainDicomTags; - params.getPublicId = GetPublicId; - params.getResourceType = GetResourceType; - params.getResourcesCount = GetResourcesCount; - params.getTotalCompressedSize = GetTotalCompressedSize; - params.getTotalUncompressedSize = GetTotalUncompressedSize; - params.isDiskSizeAbove = IsDiskSizeAbove; - params.isExistingResource = IsExistingResource; - params.isProtectedPatient = IsProtectedPatient; - params.listAvailableAttachments = ListAvailableAttachments; - params.logChange = LogChange; - params.logExportedResource = LogExportedResource; - params.lookupAttachment = LookupAttachment; - params.lookupGlobalProperty = LookupGlobalProperty; - params.lookupMetadata = LookupMetadata; - params.lookupParent = LookupParent; - params.lookupResource = LookupResource; - params.lookupResourceAndParent = LookupResourceAndParent; - params.lookupResources = LookupResources; - params.selectPatientToRecycle = SelectPatientToRecycle; - params.selectPatientToRecycle2 = SelectPatientToRecycle2; - params.setGlobalProperty = SetGlobalProperty; - params.setMetadata = SetMetadata; - params.setProtectedPatient = SetProtectedPatient; - params.setResourcesContent = SetResourcesContent; OrthancPluginContext* context = backend->GetContext(); - if (OrthancPluginRegisterDatabaseBackendV4( - context, ¶ms, sizeof(params), maxDatabaseRetries, - new Adapter(backend, countConnections)) != OrthancPluginErrorCode_Success) + if (OrthancPluginRegisterDatabaseBackendV4(context, pool.release(), maxDatabaseRetries, + CallBackend, FinalizeBackend) != OrthancPluginErrorCode_Success) { + delete backend; throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "Unable to register the database backend"); } - backend->SetOutputFactory(new Factory); - isBackendInUse_ = true; } @@ -2108,7 +1476,7 @@ { if (isBackendInUse_) { - fprintf(stderr, "The Orthanc core has not destructed the index backend, internal error\n"); + LOG(ERROR) << "The Orthanc core has not destructed the index backend, internal error"; } } }