# HG changeset patch # User Sebastien Jodogne # Date 1581352793 -3600 # Node ID f159b731c47d6460da8eacb9246d98b2a4557a88 # Parent 08eb0f93c491becb2a3f8478ac506687250cc115 IStorageCommitmentFactory diff -r 08eb0f93c491 -r f159b731c47d OrthancServer/ServerContext.cpp --- a/OrthancServer/ServerContext.cpp Mon Feb 10 16:56:28 2020 +0100 +++ b/OrthancServer/ServerContext.cpp Mon Feb 10 17:39:53 2020 +0100 @@ -1052,4 +1052,22 @@ } #endif } + + + IStorageCommitmentFactory::ILookupHandler* + ServerContext::CreateStorageCommitment(const std::string& jobId, + const std::string& transactionUid, + const std::vector& sopClassUids, + const std::vector& sopInstanceUids) + { +#if ORTHANC_ENABLE_PLUGINS == 1 + if (HasPlugins()) + { + // TODO + return NULL; + } +#endif + + return NULL; + } } diff -r 08eb0f93c491 -r f159b731c47d OrthancServer/ServerContext.h --- a/OrthancServer/ServerContext.h Mon Feb 10 16:56:28 2020 +0100 +++ b/OrthancServer/ServerContext.h Mon Feb 10 17:39:53 2020 +0100 @@ -37,6 +37,7 @@ #include "LuaScripting.h" #include "OrthancHttpHandler.h" #include "ServerIndex.h" +#include "ServerJobs/IStorageCommitmentFactory.h" #include "../Core/Cache/MemoryCache.h" @@ -60,7 +61,9 @@ * filesystem (including compression), as well as the index of the * DICOM store. It implements the required locking mechanisms. **/ - class ServerContext : private JobsRegistry::IObserver + class ServerContext : + public IStorageCommitmentFactory, + private JobsRegistry::IObserver { public: class ILookupVisitor : public boost::noncopyable @@ -424,5 +427,11 @@ { return isExecuteLuaEnabled_; } + + virtual IStorageCommitmentFactory::ILookupHandler* + CreateStorageCommitment(const std::string& jobId, + const std::string& transactionUid, + const std::vector& sopClassUids, + const std::vector& sopInstanceUids) ORTHANC_OVERRIDE; }; } diff -r 08eb0f93c491 -r f159b731c47d OrthancServer/ServerJobs/IStorageCommitmentFactory.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/ServerJobs/IStorageCommitmentFactory.h Mon Feb 10 17:39:53 2020 +0100 @@ -0,0 +1,64 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., 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 + +namespace Orthanc +{ + class IStorageCommitmentFactory : public boost::noncopyable + { + public: + class ILookupHandler : public boost::noncopyable + { + public: + virtual ~ILookupHandler() + { + } + + virtual StorageCommitmentFailureReason Lookup(const std::string& sopClassUid, + const std::string& sopInstanceUid) = 0; + }; + + virtual ~IStorageCommitmentFactory() + { + } + + virtual ILookupHandler* CreateStorageCommitment(const std::string& jobId, + const std::string& transactionUid, + const std::vector& sopClassUids, + const std::vector& sopInstanceUids) = 0; + }; +} diff -r 08eb0f93c491 -r f159b731c47d OrthancServer/ServerJobs/StorageCommitmentScpJob.cpp --- a/OrthancServer/ServerJobs/StorageCommitmentScpJob.cpp Mon Feb 10 16:56:28 2020 +0100 +++ b/OrthancServer/ServerJobs/StorageCommitmentScpJob.cpp Mon Feb 10 17:39:53 2020 +0100 @@ -66,11 +66,11 @@ class StorageCommitmentScpJob::SetupCommand : public StorageCommitmentCommand { private: - ServerContext& context_; + StorageCommitmentScpJob& that_; public: - SetupCommand(ServerContext& context) : - context_(context) + SetupCommand(StorageCommitmentScpJob& that) : + that_(that) { } @@ -81,6 +81,7 @@ virtual bool Execute(const std::string& jobId) ORTHANC_OVERRIDE { + that_.Setup(jobId); return true; } @@ -95,17 +96,17 @@ class StorageCommitmentScpJob::LookupCommand : public StorageCommitmentCommand { private: - ServerContext& context_; + StorageCommitmentScpJob& that_; bool hasFailureReason_; std::string sopClassUid_; std::string sopInstanceUid_; StorageCommitmentFailureReason failureReason_; public: - LookupCommand(ServerContext& context, + LookupCommand(StorageCommitmentScpJob& that, const std::string& sopClassUid, const std::string& sopInstanceUid) : - context_(context), + that_(that), hasFailureReason_(false), sopClassUid_(sopClassUid), sopInstanceUid_(sopInstanceUid) @@ -123,44 +124,12 @@ { throw OrthancException(ErrorCode_BadSequenceOfCalls); } - - bool success = false; - - try + else { - std::vector orthancId; - context_.GetIndex().LookupIdentifierExact(orthancId, ResourceType_Instance, DICOM_TAG_SOP_INSTANCE_UID, sopInstanceUid_); - - if (orthancId.size() == 1) - { - std::string a, b; - - // Make sure that the DICOM file can be re-read by DCMTK - // from the file storage, and that the actual SOP - // class/instance UIDs do match - ServerContext::DicomCacheLocker locker(context_, orthancId[0]); - if (locker.GetDicom().GetTagValue(a, DICOM_TAG_SOP_CLASS_UID) && - locker.GetDicom().GetTagValue(b, DICOM_TAG_SOP_INSTANCE_UID) && - a == sopClassUid_ && - b == sopInstanceUid_) - { - success = true; - } - } + failureReason_ = that_.Lookup(sopClassUid_, sopInstanceUid_); + hasFailureReason_ = true; + return true; } - catch (OrthancException&) - { - } - - LOG(INFO) << " Storage commitment SCP job: " << (success ? "Success" : "Failure") - << " while looking for " << sopClassUid_ << " / " << sopInstanceUid_; - - failureReason_ = (success ? - StorageCommitmentFailureReason_Success : - StorageCommitmentFailureReason_NoSuchObjectInstance /* 0x0112 == 274 */); - hasFailureReason_ = true; - - return true; } const std::string& GetSopClassUid() const @@ -237,13 +206,10 @@ { private: StorageCommitmentScpJob& that_; - ServerContext& context_; public: - Unserializer(StorageCommitmentScpJob& that, - ServerContext& context) : - that_(that), - context_(context) + Unserializer(StorageCommitmentScpJob& that) : + that_(that) { that_.ready_ = false; } @@ -254,11 +220,11 @@ if (type == SETUP) { - return new SetupCommand(context_); + return new SetupCommand(that_); } else if (type == LOOKUP) { - return new LookupCommand(context_, + return new LookupCommand(that_, SerializationToolbox::ReadString(source, SOP_CLASS_UID), SerializationToolbox::ReadString(source, SOP_INSTANCE_UID)); } @@ -273,6 +239,92 @@ } }; + + void StorageCommitmentScpJob::Setup(const std::string& jobId) + { + const size_t n = GetCommandsCount(); + + if (n <= 1) + { + throw OrthancException(ErrorCode_InternalError); + } + + std::vector sopClassUids, sopInstanceUids; + + sopClassUids.reserve(n); + sopInstanceUids.reserve(n); + + for (size_t i = 0; i < n; i++) + { + const CommandType type = dynamic_cast(GetCommand(i)).GetType(); + + if ((i == 0 && type != CommandType_Setup) || + (i >= 1 && i < n - 1 && type != CommandType_Lookup) || + (i == n - 1 && type != CommandType_Answer)) + { + throw OrthancException(ErrorCode_InternalError); + } + + if (type == CommandType_Lookup) + { + const LookupCommand& lookup = dynamic_cast(GetCommand(i)); + sopClassUids.push_back(lookup.GetSopClassUid()); + sopInstanceUids.push_back(lookup.GetSopInstanceUid()); + } + } + + lookupHandler_.reset(context_.CreateStorageCommitment(jobId, transactionUid_, sopClassUids, sopInstanceUids)); + } + + + StorageCommitmentFailureReason StorageCommitmentScpJob::Lookup(const std::string& sopClassUid, + const std::string& sopInstanceUid) + { + if (lookupHandler_.get() != NULL) + { + return lookupHandler_->Lookup(sopClassUid, sopInstanceUid); + } + else + { + // This is the default implementation of Orthanc (if no storage + // commitment plugin is installed) + bool success = false; + + try + { + std::vector orthancId; + context_.GetIndex().LookupIdentifierExact(orthancId, ResourceType_Instance, DICOM_TAG_SOP_INSTANCE_UID, sopInstanceUid); + + if (orthancId.size() == 1) + { + std::string a, b; + + // Make sure that the DICOM file can be re-read by DCMTK + // from the file storage, and that the actual SOP + // class/instance UIDs do match + ServerContext::DicomCacheLocker locker(context_, orthancId[0]); + if (locker.GetDicom().GetTagValue(a, DICOM_TAG_SOP_CLASS_UID) && + locker.GetDicom().GetTagValue(b, DICOM_TAG_SOP_INSTANCE_UID) && + a == sopClassUid && + b == sopInstanceUid) + { + success = true; + } + } + } + catch (OrthancException&) + { + } + + LOG(INFO) << " Storage commitment SCP job: " << (success ? "Success" : "Failure") + << " while looking for " << sopClassUid << " / " << sopInstanceUid; + + return (success ? + StorageCommitmentFailureReason_Success : + StorageCommitmentFailureReason_NoSuchObjectInstance /* 0x0112 == 274 */); + } + } + void StorageCommitmentScpJob::Answer() { @@ -335,7 +387,7 @@ } } - AddCommand(new SetupCommand(context)); + AddCommand(new SetupCommand(*this)); } @@ -348,7 +400,7 @@ } else { - AddCommand(new LookupCommand(context_, sopClassUid, sopInstanceUid)); + AddCommand(new LookupCommand(*this, sopClassUid, sopInstanceUid)); } } @@ -371,7 +423,7 @@ StorageCommitmentScpJob::StorageCommitmentScpJob(ServerContext& context, const Json::Value& serialized) : - SetOfCommandsJob(new Unserializer(*this, context), serialized), + SetOfCommandsJob(new Unserializer(*this), serialized), context_(context) { transactionUid_ = SerializationToolbox::ReadString(serialized, TRANSACTION_UID); diff -r 08eb0f93c491 -r f159b731c47d OrthancServer/ServerJobs/StorageCommitmentScpJob.h --- a/OrthancServer/ServerJobs/StorageCommitmentScpJob.h Mon Feb 10 16:56:28 2020 +0100 +++ b/OrthancServer/ServerJobs/StorageCommitmentScpJob.h Mon Feb 10 17:39:53 2020 +0100 @@ -35,7 +35,9 @@ #include "../../Core/DicomNetworking/RemoteModalityParameters.h" #include "../../Core/JobsEngine/SetOfCommandsJob.h" +#include "IStorageCommitmentFactory.h" +#include #include namespace Orthanc @@ -64,6 +66,13 @@ RemoteModalityParameters remoteModality_; std::string calledAet_; + std::auto_ptr lookupHandler_; + + void Setup(const std::string& jobId); + + StorageCommitmentFailureReason Lookup(const std::string& sopClassUid, + const std::string& sopInstanceUid); + void Answer(); public: