changeset 3660:f159b731c47d storage-commitment

IStorageCommitmentFactory
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 10 Feb 2020 17:39:53 +0100
parents 08eb0f93c491
children 25117919a36b
files OrthancServer/ServerContext.cpp OrthancServer/ServerContext.h OrthancServer/ServerJobs/IStorageCommitmentFactory.h OrthancServer/ServerJobs/StorageCommitmentScpJob.cpp OrthancServer/ServerJobs/StorageCommitmentScpJob.h
diffstat 5 files changed, 205 insertions(+), 53 deletions(-) [+]
line wrap: on
line diff
--- 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<std::string>& sopClassUids,
+                                         const std::vector<std::string>& sopInstanceUids)
+  {
+#if ORTHANC_ENABLE_PLUGINS == 1
+    if (HasPlugins())
+    {
+      // TODO
+      return NULL;
+    }
+#endif
+
+    return NULL;
+  }
 }
--- 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<std::string>& sopClassUids,
+                            const std::vector<std::string>& sopInstanceUids) ORTHANC_OVERRIDE;
   };
 }
--- /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 <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+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<std::string>& sopClassUids,
+                                                    const std::vector<std::string>& sopInstanceUids) = 0;
+  };
+}
--- 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<std::string> 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<std::string> sopClassUids, sopInstanceUids;
+
+    sopClassUids.reserve(n);
+    sopInstanceUids.reserve(n);
+
+    for (size_t i = 0; i < n; i++)
+    {
+      const CommandType type = dynamic_cast<const StorageCommitmentCommand&>(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<const LookupCommand&>(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<std::string> 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);
--- 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 <memory>
 #include <vector>
 
 namespace Orthanc
@@ -64,6 +66,13 @@
     RemoteModalityParameters  remoteModality_;
     std::string               calledAet_;
 
+    std::auto_ptr<IStorageCommitmentFactory::ILookupHandler>  lookupHandler_;
+
+    void Setup(const std::string& jobId);
+    
+    StorageCommitmentFailureReason Lookup(const std::string& sopClassUid,
+                                          const std::string& sopInstanceUid);
+    
     void Answer();
     
   public: