# HG changeset patch # User Sebastien Jodogne # Date 1443714283 -7200 # Node ID 2f2e2ec17bc474b9694e7e035020bb065409940a # Parent 16955f8fec4d0be45827ff2171fed3c34ee68b5f sample database plugin diff -r 16955f8fec4d -r 2f2e2ec17bc4 CMakeLists.txt --- a/CMakeLists.txt Thu Oct 01 14:03:07 2015 +0200 +++ b/CMakeLists.txt Thu Oct 01 17:44:43 2015 +0200 @@ -10,8 +10,8 @@ # * Orthanc 0.3.1 = version 2 # * Orthanc 0.4.0 -> Orthanc 0.7.2 = version 3 # * Orthanc 0.7.3 -> Orthanc 0.8.4 = version 4 -# * Orthanc 0.8.5 -> Orthanc 0.9.3 = version 5 -# * Orthanc 0.9.4 -> mainline = version 6 +# * Orthanc 0.8.5 -> Orthanc 0.9.4 = version 5 +# * Orthanc 0.9.5 -> mainline = version 6 set(ORTHANC_DATABASE_VERSION 6) diff -r 16955f8fec4d -r 2f2e2ec17bc4 OrthancServer/DatabaseWrapper.cpp --- a/OrthancServer/DatabaseWrapper.cpp Thu Oct 01 14:03:07 2015 +0200 +++ b/OrthancServer/DatabaseWrapper.cpp Thu Oct 01 17:44:43 2015 +0200 @@ -386,6 +386,92 @@ } + bool DatabaseWrapper::LookupParent(int64_t& parentId, + int64_t resourceId) + { + bool found; + ErrorCode error = base_.LookupParent(found, parentId, resourceId); + + if (error != ErrorCode_Success) + { + throw OrthancException(error); + } + else + { + return found; + } + } + + + ResourceType DatabaseWrapper::GetResourceType(int64_t resourceId) + { + ResourceType result; + ErrorCode code = base_.GetResourceType(result, resourceId); + + if (code == ErrorCode_Success) + { + return result; + } + else + { + throw OrthancException(code); + } + } + + + std::string DatabaseWrapper::GetPublicId(int64_t resourceId) + { + std::string id; + + if (base_.GetPublicId(id, resourceId)) + { + return id; + } + else + { + throw OrthancException(ErrorCode_UnknownResource); + } + } + + + void DatabaseWrapper::GetChanges(std::list& target /*out*/, + bool& done /*out*/, + int64_t since, + uint32_t maxResults) + { + ErrorCode code = base_.GetChanges(target, done, since, maxResults); + + if (code != ErrorCode_Success) + { + throw OrthancException(code); + } + } + + + void DatabaseWrapper::GetLastChange(std::list& target /*out*/) + { + ErrorCode code = base_.GetLastChange(target); + + if (code != ErrorCode_Success) + { + throw OrthancException(code); + } + } + + + void DatabaseWrapper::LookupIdentifier(std::list& target, + const DicomTag& tag, + const std::string& value) + { + if (!tag.IsIdentifier()) + { + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + base_.LookupIdentifier(target, tag, value); + } + + void DatabaseWrapper::GetAllMetadata(std::map& target, int64_t id) { diff -r 16955f8fec4d -r 2f2e2ec17bc4 OrthancServer/DatabaseWrapper.h --- a/OrthancServer/DatabaseWrapper.h Thu Oct 01 14:03:07 2015 +0200 +++ b/OrthancServer/DatabaseWrapper.h Thu Oct 01 17:44:43 2015 +0200 @@ -96,20 +96,11 @@ } virtual bool LookupParent(int64_t& parentId, - int64_t resourceId) - { - return base_.LookupParent(parentId, resourceId); - } + int64_t resourceId); - virtual std::string GetPublicId(int64_t resourceId) - { - return base_.GetPublicId(resourceId); - } + virtual std::string GetPublicId(int64_t resourceId); - virtual ResourceType GetResourceType(int64_t resourceId) - { - return base_.GetResourceType(resourceId); - } + virtual ResourceType GetResourceType(int64_t resourceId); virtual void AttachChild(int64_t parent, int64_t child) @@ -209,15 +200,9 @@ virtual void GetChanges(std::list& target /*out*/, bool& done /*out*/, int64_t since, - uint32_t maxResults) - { - base_.GetChanges(target, done, since, maxResults); - } + uint32_t maxResults); - virtual void GetLastChange(std::list& target /*out*/) - { - base_.GetLastChange(target); - } + virtual void GetLastChange(std::list& target /*out*/); virtual void LogExportedResource(const ExportedResource& resource) { @@ -320,10 +305,7 @@ virtual void LookupIdentifier(std::list& target, const DicomTag& tag, - const std::string& value) - { - base_.LookupIdentifier(target, tag, value); - } + const std::string& value); virtual void LookupIdentifier(std::list& target, const std::string& value) diff -r 16955f8fec4d -r 2f2e2ec17bc4 OrthancServer/DatabaseWrapperBase.cpp --- a/OrthancServer/DatabaseWrapperBase.cpp Thu Oct 01 14:03:07 2015 +0200 +++ b/OrthancServer/DatabaseWrapperBase.cpp Thu Oct 01 17:44:43 2015 +0200 @@ -98,8 +98,9 @@ } } - bool DatabaseWrapperBase::LookupParent(int64_t& parentId, - int64_t resourceId) + ErrorCode DatabaseWrapperBase::LookupParent(bool& found, + int64_t& parentId, + int64_t resourceId) { SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT parentId FROM Resources WHERE internalId=?"); @@ -107,21 +108,24 @@ if (!s.Step()) { - throw OrthancException(ErrorCode_UnknownResource); + return ErrorCode_UnknownResource; } if (s.ColumnIsNull(0)) { - return false; + found = false; } else { + found = true; parentId = s.ColumnInt(0); - return true; } + + return ErrorCode_Success; } - std::string DatabaseWrapperBase::GetPublicId(int64_t resourceId) + bool DatabaseWrapperBase::GetPublicId(std::string& result, + int64_t resourceId) { SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT publicId FROM Resources WHERE internalId=?"); @@ -129,25 +133,32 @@ if (!s.Step()) { - throw OrthancException(ErrorCode_UnknownResource); + return false; } - - return s.ColumnString(0); + else + { + result = s.ColumnString(0); + return true; + } } - ResourceType DatabaseWrapperBase::GetResourceType(int64_t resourceId) + ErrorCode DatabaseWrapperBase::GetResourceType(ResourceType& result, + int64_t resourceId) { SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT resourceType FROM Resources WHERE internalId=?"); s.BindInt64(0, resourceId); - if (!s.Step()) + if (s.Step()) + { + result = static_cast(s.ColumnInt(0)); + return ErrorCode_Success; + } + else { - throw OrthancException(ErrorCode_UnknownResource); + return ErrorCode_UnknownResource; } - - return static_cast(s.ColumnInt(0)); } @@ -400,10 +411,10 @@ } - void DatabaseWrapperBase::GetChangesInternal(std::list& target, - bool& done, - SQLite::Statement& s, - uint32_t maxResults) + ErrorCode DatabaseWrapperBase::GetChangesInternal(std::list& target, + bool& done, + SQLite::Statement& s, + uint32_t maxResults) { target.clear(); @@ -415,31 +426,36 @@ const std::string& date = s.ColumnString(4); int64_t internalId = s.ColumnInt64(2); - std::string publicId = GetPublicId(internalId); + std::string publicId; + if (!GetPublicId(publicId, internalId)) + { + return ErrorCode_UnknownResource; + } target.push_back(ServerIndexChange(seq, changeType, resourceType, publicId, date)); } done = !(target.size() == maxResults && s.Step()); + return ErrorCode_Success; } - void DatabaseWrapperBase::GetChanges(std::list& target, - bool& done, - int64_t since, - uint32_t maxResults) + ErrorCode DatabaseWrapperBase::GetChanges(std::list& target, + bool& done, + int64_t since, + uint32_t maxResults) { SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT * FROM Changes WHERE seq>? ORDER BY seq LIMIT ?"); s.BindInt64(0, since); s.BindInt(1, maxResults + 1); - GetChangesInternal(target, done, s, maxResults); + return GetChangesInternal(target, done, s, maxResults); } - void DatabaseWrapperBase::GetLastChange(std::list& target) + ErrorCode DatabaseWrapperBase::GetLastChange(std::list& target) { bool done; // Ignored SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT * FROM Changes ORDER BY seq DESC LIMIT 1"); - GetChangesInternal(target, done, s, 1); + return GetChangesInternal(target, done, s, 1); } @@ -573,13 +589,14 @@ if (!s.Step()) { - throw OrthancException(ErrorCode_InternalError); + return 0; } - - int64_t c = s.ColumnInt(0); - assert(!s.Step()); - - return c; + else + { + int64_t c = s.ColumnInt(0); + assert(!s.Step()); + return c; + } } @@ -664,11 +681,6 @@ const DicomTag& tag, const std::string& value) { - if (!tag.IsIdentifier()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT id FROM DicomIdentifiers WHERE tagGroup=? AND tagElement=? and value=?"); diff -r 16955f8fec4d -r 2f2e2ec17bc4 OrthancServer/DatabaseWrapperBase.h --- a/OrthancServer/DatabaseWrapperBase.h Thu Oct 01 14:03:07 2015 +0200 +++ b/OrthancServer/DatabaseWrapperBase.h Thu Oct 01 17:44:43 2015 +0200 @@ -37,8 +37,8 @@ #include "../Core/Enumerations.h" #include "../Core/FileStorage/FileInfo.h" #include "../Core/SQLite/Connection.h" +#include "../OrthancServer/ExportedResource.h" #include "../OrthancServer/ServerIndexChange.h" -#include "../OrthancServer/ExportedResource.h" #include "ServerEnumerations.h" #include @@ -51,10 +51,10 @@ private: SQLite::Connection& db_; - void GetChangesInternal(std::list& target, - bool& done, - SQLite::Statement& s, - uint32_t maxResults); + ErrorCode GetChangesInternal(std::list& target, + bool& done, + SQLite::Statement& s, + uint32_t maxResults); void GetExportedResourcesInternal(std::list& target, bool& done, @@ -79,12 +79,15 @@ ResourceType& type, const std::string& publicId); - bool LookupParent(int64_t& parentId, - int64_t resourceId); + ErrorCode LookupParent(bool& found, + int64_t& parentId, + int64_t resourceId); - std::string GetPublicId(int64_t resourceId); + bool GetPublicId(std::string& result, + int64_t resourceId); - ResourceType GetResourceType(int64_t resourceId); + ErrorCode GetResourceType(ResourceType& result, + int64_t resourceId); void AttachChild(int64_t parent, int64_t child); @@ -136,13 +139,12 @@ void LogChange(int64_t internalId, const ServerIndexChange& change); - void GetChanges(std::list& target, - bool& done, - int64_t since, - uint32_t maxResults); + ErrorCode GetChanges(std::list& target, + bool& done, + int64_t since, + uint32_t maxResults); - void GetLastChange(std::list& target); - + ErrorCode GetLastChange(std::list& target); void LogExportedResource(const ExportedResource& resource); @@ -179,7 +181,6 @@ bool IsExistingResource(int64_t internalId); - void LookupIdentifier(std::list& target, const DicomTag& tag, const std::string& value); diff -r 16955f8fec4d -r 2f2e2ec17bc4 Plugins/Engine/PluginsEnumerations.cpp --- a/Plugins/Engine/PluginsEnumerations.cpp Thu Oct 01 14:03:07 2015 +0200 +++ b/Plugins/Engine/PluginsEnumerations.cpp Thu Oct 01 17:44:43 2015 +0200 @@ -210,7 +210,7 @@ } - +#if !defined(ORTHANC_ENABLE_DCMTK) || ORTHANC_ENABLE_DCMTK != 0 DcmEVR Convert(OrthancPluginValueRepresentation vr) { switch (vr) @@ -300,5 +300,6 @@ throw OrthancException(ErrorCode_ParameterOutOfRange); } } +#endif } } diff -r 16955f8fec4d -r 2f2e2ec17bc4 Plugins/Engine/PluginsEnumerations.h --- a/Plugins/Engine/PluginsEnumerations.h Thu Oct 01 14:03:07 2015 +0200 +++ b/Plugins/Engine/PluginsEnumerations.h Thu Oct 01 17:44:43 2015 +0200 @@ -37,7 +37,9 @@ #include "../Include/orthanc/OrthancCPlugin.h" #include "../../OrthancServer/ServerEnumerations.h" +#if !defined(ORTHANC_ENABLE_DCMTK) || ORTHANC_ENABLE_DCMTK != 0 #include +#endif namespace Orthanc { @@ -57,7 +59,9 @@ FileContentType Convert(OrthancPluginContentType type); +#if !defined(ORTHANC_ENABLE_DCMTK) || ORTHANC_ENABLE_DCMTK != 0 DcmEVR Convert(OrthancPluginValueRepresentation vr); +#endif } } diff -r 16955f8fec4d -r 2f2e2ec17bc4 Plugins/Samples/DatabasePlugin/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Samples/DatabasePlugin/CMakeLists.txt Thu Oct 01 17:44:43 2015 +0200 @@ -0,0 +1,72 @@ +cmake_minimum_required(VERSION 2.8) + +project(SampleDatabasePlugin) + +# Parameters of the build +SET(SAMPLE_DATABASE_VERSION "0.0" CACHE STRING "Version of the plugin") +SET(STATIC_BUILD OFF CACHE BOOL "Static build of the third-party libraries (necessary for Windows)") +SET(ALLOW_DOWNLOADS OFF CACHE BOOL "Allow CMake to download packages") +SET(STANDALONE_BUILD ON) + +# Advanced parameters to fine-tune linking against system libraries +SET(USE_SYSTEM_BOOST ON CACHE BOOL "Use the system version of Boost") +SET(USE_SYSTEM_JSONCPP ON CACHE BOOL "Use the system version of JsonCpp") +SET(USE_SYSTEM_SQLITE ON CACHE BOOL "Use the system version of SQLite") + +set(SAMPLES_ROOT ${CMAKE_SOURCE_DIR}/..) +include(${SAMPLES_ROOT}/Common/OrthancPlugins.cmake) + +include(${ORTHANC_ROOT}/Resources/CMake/BoostConfiguration.cmake) +include(${ORTHANC_ROOT}/Resources/CMake/JsonCppConfiguration.cmake) +include(${ORTHANC_ROOT}/Resources/CMake/SQLiteConfiguration.cmake) + +EmbedResources( + --system-exception # Use "std::runtime_error" instead of "OrthancException" for embedded resources + PREPARE_DATABASE ${ORTHANC_ROOT}/OrthancServer/PrepareDatabase.sql + ) + +message("Setting the version of the plugin to ${SAMPLE_DATABASE_VERSION}") + +add_definitions( + -DORTHANC_SQLITE_STANDALONE=1 + -DORTHANC_ENABLE_LOGGING=0 + -DORTHANC_ENABLE_BASE64=0 + -DORTHANC_ENABLE_MD5=0 + -DORTHANC_ENABLE_DCMTK=0 + -DORTHANC_PLUGINS_ENABLED=1 + -DSAMPLE_DATABASE_VERSION="${SAMPLE_DATABASE_VERSION}" + ) + +add_library(SampleDatabase SHARED + ${BOOST_SOURCES} + ${JSONCPP_SOURCES} + ${SQLITE_SOURCES} + ${AUTOGENERATED_SOURCES} + + ${ORTHANC_ROOT}/Core/DicomFormat/DicomArray.cpp + ${ORTHANC_ROOT}/Core/DicomFormat/DicomMap.cpp + ${ORTHANC_ROOT}/Core/DicomFormat/DicomTag.cpp + ${ORTHANC_ROOT}/Core/Enumerations.cpp + ${ORTHANC_ROOT}/Core/SQLite/Connection.cpp + ${ORTHANC_ROOT}/Core/SQLite/FunctionContext.cpp + ${ORTHANC_ROOT}/Core/SQLite/Statement.cpp + ${ORTHANC_ROOT}/Core/SQLite/StatementId.cpp + ${ORTHANC_ROOT}/Core/SQLite/StatementReference.cpp + ${ORTHANC_ROOT}/Core/SQLite/Transaction.cpp + ${ORTHANC_ROOT}/Core/Toolbox.cpp + ${ORTHANC_ROOT}/OrthancServer/DatabaseWrapperBase.cpp + ${ORTHANC_ROOT}/Plugins/Engine/PluginsEnumerations.cpp + + Database.cpp + Plugin.cpp + ) + +set_target_properties(SampleDatabase PROPERTIES + VERSION ${SAMPLE_DATABASE_VERSION} + SOVERSION ${SAMPLE_DATABASE_VERSION}) + +install( + TARGETS SampleDatabase + RUNTIME DESTINATION lib # Destination for Windows + LIBRARY DESTINATION share/orthanc/plugins # Destination for Linux + ) diff -r 16955f8fec4d -r 2f2e2ec17bc4 Plugins/Samples/DatabasePlugin/Database.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Samples/DatabasePlugin/Database.cpp Thu Oct 01 17:44:43 2015 +0200 @@ -0,0 +1,510 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#include "Database.h" + +#include + +#include "../../../Core/DicomFormat/DicomArray.h" + +namespace Internals +{ + class SignalFileDeleted : public Orthanc::SQLite::IScalarFunction + { + private: + OrthancPlugins::DatabaseBackendOutput& output_; + + public: + SignalFileDeleted(OrthancPlugins::DatabaseBackendOutput& output) : output_(output) + { + } + + virtual const char* GetName() const + { + return "SignalFileDeleted"; + } + + virtual unsigned int GetCardinality() const + { + return 7; + } + + virtual void Compute(Orthanc::SQLite::FunctionContext& context) + { + std::string uncompressedMD5, compressedMD5; + + if (!context.IsNullValue(5)) + { + uncompressedMD5 = context.GetStringValue(5); + } + + if (!context.IsNullValue(6)) + { + compressedMD5 = context.GetStringValue(6); + } + + output_.SignalDeletedAttachment(context.GetStringValue(0), + context.GetIntValue(1), + context.GetInt64Value(2), + uncompressedMD5, + context.GetIntValue(3), + context.GetInt64Value(4), + compressedMD5); + } + }; + + + class SignalResourceDeleted : public Orthanc::SQLite::IScalarFunction + { + private: + OrthancPlugins::DatabaseBackendOutput& output_; + + public: + SignalResourceDeleted(OrthancPlugins::DatabaseBackendOutput& output) : output_(output) + { + } + + virtual const char* GetName() const + { + return "SignalResourceDeleted"; + } + + virtual unsigned int GetCardinality() const + { + return 2; + } + + virtual void Compute(Orthanc::SQLite::FunctionContext& context) + { + output_.SignalDeletedResource(context.GetStringValue(0), + static_cast(context.GetIntValue(1))); + } + }; +} + + +class Database::SignalRemainingAncestor : public Orthanc::SQLite::IScalarFunction +{ +private: + bool hasRemainingAncestor_; + std::string remainingPublicId_; + Orthanc::ResourceType remainingType_; + +public: + SignalRemainingAncestor() : + hasRemainingAncestor_(false) + { + } + + void Reset() + { + hasRemainingAncestor_ = false; + } + + virtual const char* GetName() const + { + return "SignalRemainingAncestor"; + } + + virtual unsigned int GetCardinality() const + { + return 2; + } + + virtual void Compute(Orthanc::SQLite::FunctionContext& context) + { + if (!hasRemainingAncestor_ || + remainingType_ >= context.GetIntValue(1)) + { + hasRemainingAncestor_ = true; + remainingPublicId_ = context.GetStringValue(0); + remainingType_ = static_cast(context.GetIntValue(1)); + } + } + + bool HasRemainingAncestor() const + { + return hasRemainingAncestor_; + } + + const std::string& GetRemainingAncestorId() const + { + assert(hasRemainingAncestor_); + return remainingPublicId_; + } + + Orthanc::ResourceType GetRemainingAncestorType() const + { + assert(hasRemainingAncestor_); + return remainingType_; + } +}; + + + +Database::Database(const std::string& path) : + path_(path), + base_(db_) +{ + db_.Open(path_); + Open(); +} + + +void Database::Open() +{ + if (!db_.DoesTableExist("GlobalProperties")) + { + std::string query; + Orthanc::EmbeddedResources::GetFileResource(query, Orthanc::EmbeddedResources::PREPARE_DATABASE); + db_.Execute(query); + } + + signalRemainingAncestor_ = new SignalRemainingAncestor; + db_.Register(signalRemainingAncestor_); + db_.Register(new Internals::SignalFileDeleted(GetOutput())); + db_.Register(new Internals::SignalResourceDeleted(GetOutput())); +} + + +void Database::Close() +{ + db_.Close(); +} + + +void Database::AddAttachment(int64_t id, + const OrthancPluginAttachment& attachment) +{ + Orthanc::FileInfo info(attachment.uuid, + static_cast(attachment.contentType), + attachment.uncompressedSize, + attachment.uncompressedHash, + static_cast(attachment.compressionType), + attachment.compressedSize, + attachment.compressedHash); + base_.AddAttachment(id, info); +} + + +void Database::DeleteResource(int64_t id) +{ + // TODO +} + + +static void Answer(OrthancPlugins::DatabaseBackendOutput& output, + const Orthanc::ServerIndexChange& change) +{ + output.AnswerChange(change.GetSeq(), + static_cast(change.GetChangeType()), + Orthanc::Plugins::Convert(change.GetResourceType()), + change.GetPublicId(), + change.GetDate()); +} + + +static void Answer(OrthancPlugins::DatabaseBackendOutput& output, + const Orthanc::ExportedResource& resource) +{ + output.AnswerExportedResource(resource.GetSeq(), + Orthanc::Plugins::Convert(resource.GetResourceType()), + resource.GetPublicId(), + resource.GetModality(), + resource.GetDate(), + resource.GetPatientId(), + resource.GetStudyInstanceUid(), + resource.GetSeriesInstanceUid(), + resource.GetSopInstanceUid()); +} + + +void Database::GetChanges(bool& done /*out*/, + int64_t since, + uint32_t maxResults) +{ + typedef std::list Changes; + + Changes changes; + base_.GetChanges(changes, done, since, maxResults); + + for (Changes::const_iterator it = changes.begin(); it != changes.end(); ++it) + { + Answer(GetOutput(), *it); + } +} + + +void Database::GetExportedResources(bool& done /*out*/, + int64_t since, + uint32_t maxResults) +{ + typedef std::list Resources; + + Resources resources; + base_.GetExportedResources(resources, done, since, maxResults); + + for (Resources::const_iterator it = resources.begin(); it != resources.end(); ++it) + { + Answer(GetOutput(), *it); + } +} + + +void Database::GetLastChange() +{ + std::list change; + Orthanc::ErrorCode code = base_.GetLastChange(change); + + if (code != Orthanc::ErrorCode_Success) + { + throw OrthancPlugins::DatabaseException(static_cast(code)); + } + + if (!change.empty()) + { + Answer(GetOutput(), change.front()); + } +} + + +void Database::GetLastExportedResource() +{ + std::list resource; + base_.GetLastExportedResource(resource); + + if (!resource.empty()) + { + Answer(GetOutput(), resource.front()); + } +} + + +void Database::GetMainDicomTags(int64_t id) +{ + Orthanc::DicomMap tags; + base_.GetMainDicomTags(tags, id); + + Orthanc::DicomArray arr(tags); + for (size_t i = 0; i < arr.GetSize(); i++) + { + GetOutput().AnswerDicomTag(arr.GetElement(i).GetTag().GetGroup(), + arr.GetElement(i).GetTag().GetElement(), + arr.GetElement(i).GetValue().AsString()); + } +} + + +std::string Database::GetPublicId(int64_t resourceId) +{ + std::string id; + if (base_.GetPublicId(id, resourceId)) + { + return id; + } + else + { + throw OrthancPlugins::DatabaseException(OrthancPluginErrorCode_UnknownResource); + } +} + + +OrthancPluginResourceType Database::GetResourceType(int64_t resourceId) +{ + Orthanc::ResourceType result; + Orthanc::ErrorCode code = base_.GetResourceType(result, resourceId); + + if (code == Orthanc::ErrorCode_Success) + { + return Orthanc::Plugins::Convert(result); + } + else + { + throw OrthancPlugins::DatabaseException(static_cast(code)); + } +} + + + +template +static void ConvertList(std::list& target, + const std::list& source) +{ + for (typename std::list::const_iterator + it = source.begin(); it != source.end(); it++) + { + target.push_back(*it); + } +} + + +void Database::ListAvailableMetadata(std::list& target /*out*/, + int64_t id) +{ + std::list tmp; + base_.ListAvailableMetadata(tmp, id); + ConvertList(target, tmp); +} + + +void Database::ListAvailableAttachments(std::list& target /*out*/, + int64_t id) +{ + std::list tmp; + base_.ListAvailableAttachments(tmp, id); + ConvertList(target, tmp); +} + + +void Database::LogChange(const OrthancPluginChange& change) +{ + int64_t id; + OrthancPluginResourceType type; + if (!LookupResource(id, type, change.publicId) || + type != change.resourceType) + { + throw OrthancPlugins::DatabaseException(OrthancPluginErrorCode_DatabasePlugin); + } + + Orthanc::ServerIndexChange tmp(change.seq, + static_cast(change.changeType), + Orthanc::Plugins::Convert(change.resourceType), + change.publicId, + change.date); + + base_.LogChange(id, tmp); +} + + +void Database::LogExportedResource(const OrthancPluginExportedResource& resource) +{ + Orthanc::ExportedResource tmp(resource.seq, + Orthanc::Plugins::Convert(resource.resourceType), + resource.publicId, + resource.modality, + resource.date, + resource.patientId, + resource.studyInstanceUid, + resource.seriesInstanceUid, + resource.sopInstanceUid); + + base_.LogExportedResource(tmp); +} + + +bool Database::LookupAttachment(int64_t id, + int32_t contentType) +{ + Orthanc::FileInfo attachment; + if (base_.LookupAttachment(attachment, id, static_cast(contentType))) + { + GetOutput().AnswerAttachment(attachment.GetUuid(), + attachment.GetContentType(), + attachment.GetUncompressedSize(), + attachment.GetUncompressedMD5(), + attachment.GetCompressionType(), + attachment.GetCompressedSize(), + attachment.GetCompressedMD5()); + return true; + } + else + { + return false; + } +} + + +bool Database::LookupParent(int64_t& parentId /*out*/, + int64_t resourceId) +{ + bool found; + Orthanc::ErrorCode code = base_.LookupParent(found, parentId, resourceId); + + if (code == Orthanc::ErrorCode_Success) + { + return found; + } + else + { + throw OrthancPlugins::DatabaseException(static_cast(code)); + } +} + + +bool Database::LookupResource(int64_t& id /*out*/, + OrthancPluginResourceType& type /*out*/, + const char* publicId) +{ + Orthanc::ResourceType tmp; + if (base_.LookupResource(id, tmp, publicId)) + { + type = Orthanc::Plugins::Convert(tmp); + return true; + } + else + { + return false; + } +} + + +void Database::StartTransaction() +{ + transaction_.reset(new Orthanc::SQLite::Transaction(db_)); + transaction_->Begin(); +} + + +void Database::RollbackTransaction() +{ + transaction_->Rollback(); + transaction_.reset(NULL); +} + + +void Database::CommitTransaction() +{ + transaction_->Commit(); + transaction_.reset(NULL); +} + + +uint32_t Database::GetDatabaseVersion() +{ + return 6; +} + + +void Database::UpgradeDatabase(uint32_t targetVersion, + OrthancPluginStorageArea* storageArea) +{ +} diff -r 16955f8fec4d -r 2f2e2ec17bc4 Plugins/Samples/DatabasePlugin/Database.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Samples/DatabasePlugin/Database.h Thu Oct 01 17:44:43 2015 +0200 @@ -0,0 +1,280 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include + +#include "../../../Core/SQLite/Connection.h" +#include "../../../Core/SQLite/Transaction.h" +#include "../../../OrthancServer/DatabaseWrapperBase.h" +#include "../../Engine/PluginsEnumerations.h" + +#include + +class Database : public OrthancPlugins::IDatabaseBackend +{ +private: + class SignalRemainingAncestor; + + std::string path_; + Orthanc::SQLite::Connection db_; + Orthanc::DatabaseWrapperBase base_; + SignalRemainingAncestor* signalRemainingAncestor_; + + std::auto_ptr transaction_; + +public: + Database(const std::string& path); + + virtual void Open(); + + virtual void Close(); + + virtual void AddAttachment(int64_t id, + const OrthancPluginAttachment& attachment); + + virtual void AttachChild(int64_t parent, + int64_t child) + { + base_.AttachChild(parent, child); + } + + virtual void ClearChanges() + { + db_.Execute("DELETE FROM Changes"); + } + + virtual void ClearExportedResources() + { + db_.Execute("DELETE FROM ExportedResources"); + } + + virtual int64_t CreateResource(const char* publicId, + OrthancPluginResourceType type) + { + return base_.CreateResource(publicId, Orthanc::Plugins::Convert(type)); + } + + virtual void DeleteAttachment(int64_t id, + int32_t attachment) + { + base_.DeleteAttachment(id, static_cast(attachment)); + } + + virtual void DeleteMetadata(int64_t id, + int32_t metadataType) + { + base_.DeleteMetadata(id, static_cast(metadataType)); + } + + virtual void DeleteResource(int64_t id); + + virtual void GetAllPublicIds(std::list& target, + OrthancPluginResourceType resourceType) + { + base_.GetAllPublicIds(target, Orthanc::Plugins::Convert(resourceType)); + } + + virtual void GetAllPublicIds(std::list& target, + OrthancPluginResourceType resourceType, + uint64_t since, + uint64_t limit) + { + base_.GetAllPublicIds(target, Orthanc::Plugins::Convert(resourceType), since, limit); + } + + virtual void GetChanges(bool& done /*out*/, + int64_t since, + uint32_t maxResults); + + virtual void GetChildrenInternalId(std::list& target /*out*/, + int64_t id) + { + base_.GetChildrenInternalId(target, id); + } + + virtual void GetChildrenPublicId(std::list& target /*out*/, + int64_t id) + { + base_.GetChildrenPublicId(target, id); + } + + virtual void GetExportedResources(bool& done /*out*/, + int64_t since, + uint32_t maxResults); + + virtual void GetLastChange(); + + virtual void GetLastExportedResource(); + + virtual void GetMainDicomTags(int64_t id); + + virtual std::string GetPublicId(int64_t resourceId); + + virtual uint64_t GetResourceCount(OrthancPluginResourceType resourceType) + { + return base_.GetResourceCount(Orthanc::Plugins::Convert(resourceType)); + } + + virtual OrthancPluginResourceType GetResourceType(int64_t resourceId); + + virtual uint64_t GetTotalCompressedSize() + { + return base_.GetTotalCompressedSize(); + } + + virtual uint64_t GetTotalUncompressedSize() + { + return base_.GetTotalUncompressedSize(); + } + + virtual bool IsExistingResource(int64_t internalId) + { + return base_.IsExistingResource(internalId); + } + + virtual bool IsProtectedPatient(int64_t internalId) + { + return base_.IsProtectedPatient(internalId); + } + + virtual void ListAvailableMetadata(std::list& target /*out*/, + int64_t id); + + virtual void ListAvailableAttachments(std::list& target /*out*/, + int64_t id); + + virtual void LogChange(const OrthancPluginChange& change); + + virtual void LogExportedResource(const OrthancPluginExportedResource& resource); + + virtual bool LookupAttachment(int64_t id, + int32_t contentType); + + virtual bool LookupGlobalProperty(std::string& target /*out*/, + int32_t property) + { + return base_.LookupGlobalProperty(target, static_cast(property)); + } + + virtual void LookupIdentifier(std::list& target /*out*/, + uint16_t group, + uint16_t element, + const char* value) + { + base_.LookupIdentifier(target, Orthanc::DicomTag(group, element), value); + } + + virtual void LookupIdentifier(std::list& target /*out*/, + const char* value) + { + base_.LookupIdentifier(target, value); + } + + virtual bool LookupMetadata(std::string& target /*out*/, + int64_t id, + int32_t metadataType) + { + return base_.LookupMetadata(target, id, static_cast(metadataType)); + } + + virtual bool LookupParent(int64_t& parentId /*out*/, + int64_t resourceId); + + virtual bool LookupResource(int64_t& id /*out*/, + OrthancPluginResourceType& type /*out*/, + const char* publicId); + + virtual bool SelectPatientToRecycle(int64_t& internalId /*out*/) + { + return base_.SelectPatientToRecycle(internalId); + } + + virtual bool SelectPatientToRecycle(int64_t& internalId /*out*/, + int64_t patientIdToAvoid) + { + return base_.SelectPatientToRecycle(internalId, patientIdToAvoid); + } + + + virtual void SetGlobalProperty(int32_t property, + const char* value) + { + base_.SetGlobalProperty(static_cast(property), value); + } + + virtual void SetMainDicomTag(int64_t id, + uint16_t group, + uint16_t element, + const char* value) + { + base_.SetMainDicomTag(id, Orthanc::DicomTag(group, element), value); + } + + virtual void SetIdentifierTag(int64_t id, + uint16_t group, + uint16_t element, + const char* value) + { + base_.SetMainDicomTag(id, Orthanc::DicomTag(group, element), value); + } + + virtual void SetMetadata(int64_t id, + int32_t metadataType, + const char* value) + { + base_.SetMetadata(id, static_cast(metadataType), value); + } + + virtual void SetProtectedPatient(int64_t internalId, + bool isProtected) + { + base_.SetProtectedPatient(internalId, isProtected); + } + + virtual void StartTransaction(); + + virtual void RollbackTransaction(); + + virtual void CommitTransaction(); + + virtual uint32_t GetDatabaseVersion(); + + virtual void UpgradeDatabase(uint32_t targetVersion, + OrthancPluginStorageArea* storageArea); + + virtual void ClearMainDicomTags(int64_t internalId) + { + base_.ClearMainDicomTags(internalId); + } +}; diff -r 16955f8fec4d -r 2f2e2ec17bc4 Plugins/Samples/DatabasePlugin/Plugin.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Samples/DatabasePlugin/Plugin.cpp Thu Oct 01 17:44:43 2015 +0200 @@ -0,0 +1,101 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#include "Database.h" + +#include +#include +#include + +static OrthancPluginContext* context_ = NULL; +static std::auto_ptr backend_; + + +extern "C" +{ + ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* c) + { + context_ = c; + OrthancPluginLogWarning(context_, "Sample plugin is initializing"); + + /* Check the version of the Orthanc core */ + if (OrthancPluginCheckVersion(c) == 0) + { + char info[256]; + sprintf(info, "Your version of Orthanc (%s) must be above %d.%d.%d to run this plugin", + c->orthancVersion, + ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER, + ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER, + ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER); + OrthancPluginLogError(context_, info); + return -1; + } + + std::string path = "SampleDatabase.sqlite"; + uint32_t argCount = OrthancPluginGetCommandLineArgumentsCount(context_); + for (uint32_t i = 0; i < argCount; i++) + { + char* tmp = OrthancPluginGetCommandLineArgument(context_, i); + std::string argument(tmp); + OrthancPluginFreeString(context_, tmp); + + if (boost::starts_with(argument, "--database=")) + { + path = argument.substr(11); + } + } + + std::string s = "Using the following SQLite database: " + path; + OrthancPluginLogWarning(context_, s.c_str()); + + backend_.reset(new Database(path)); + OrthancPlugins::DatabaseBackendAdapter::Register(context_, *backend_); + + return 0; + } + + ORTHANC_PLUGINS_API void OrthancPluginFinalize() + { + backend_.reset(NULL); + } + + ORTHANC_PLUGINS_API const char* OrthancPluginGetName() + { + return "sample-database"; + } + + + ORTHANC_PLUGINS_API const char* OrthancPluginGetVersion() + { + return "1.0"; + } +}