diff OrthancServer/ServerJobs/StorageCommitmentScpJob.cpp @ 3657:115f82775c46 storage-commitment

handling of storage commitment failure reasons
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 10 Feb 2020 14:53:36 +0100
parents fddf3fc82362
children 2d90dd30858c
line wrap: on
line diff
--- a/OrthancServer/ServerJobs/StorageCommitmentScpJob.cpp	Mon Feb 10 10:37:10 2020 +0100
+++ b/OrthancServer/ServerJobs/StorageCommitmentScpJob.cpp	Mon Feb 10 14:53:36 2020 +0100
@@ -44,14 +44,10 @@
 
 static const char* ANSWER = "Answer";
 static const char* CALLED_AET = "CalledAet";
-static const char* FAILED_SOP_CLASS_UIDS = "FailedSopClassUids";
-static const char* FAILED_SOP_INSTANCE_UIDS = "FailedSopInstanceUids";
 static const char* LOOKUP = "Lookup";
 static const char* REMOTE_MODALITY = "RemoteModality";
 static const char* SOP_CLASS_UID = "SopClassUid";
 static const char* SOP_INSTANCE_UID = "SopInstanceUid";
-static const char* SUCCESS_SOP_CLASS_UIDS = "SuccessSopClassUids";
-static const char* SUCCESS_SOP_INSTANCE_UIDS = "SuccessSopInstanceUids";
 static const char* TRANSACTION_UID = "TransactionUid";
 static const char* TYPE = "Type";
 
@@ -59,29 +55,106 @@
 
 namespace Orthanc
 {
-  class StorageCommitmentScpJob::LookupCommand : public SetOfCommandsJob::ICommand
+  class StorageCommitmentScpJob::StorageCommitmentCommand : public SetOfCommandsJob::ICommand
+  {
+  public:
+    virtual bool IsAnswer() const = 0;
+  };
+
+  
+  class StorageCommitmentScpJob::LookupCommand : public StorageCommitmentCommand
   {
   private:
-    StorageCommitmentScpJob&  that_;
-    std::string               sopClassUid_;
-    std::string               sopInstanceUid_;
+    ServerContext&  context_;
+    bool            hasFailureReason_;
+    std::string     sopClassUid_;
+    std::string     sopInstanceUid_;
+    StorageCommitmentFailureReason  failureReason_;
 
   public:
-    LookupCommand(StorageCommitmentScpJob& that,
+    LookupCommand(ServerContext& context,
                   const std::string& sopClassUid,
                   const std::string& sopInstanceUid) :
-      that_(that),
+      context_(context),
+      hasFailureReason_(false),
       sopClassUid_(sopClassUid),
       sopInstanceUid_(sopInstanceUid)
     {
     }
 
+    virtual bool IsAnswer() const
+    {
+      return false;
+    }
+    
     virtual bool Execute()
     {
-      that_.LookupInstance(sopClassUid_, sopInstanceUid_);
+      if (hasFailureReason_)
+      {
+        throw OrthancException(ErrorCode_BadSequenceOfCalls);
+      }
+      
+      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_;
+
+      failureReason_ = (success ?
+                        StorageCommitmentFailureReason_Success : 
+                        StorageCommitmentFailureReason_NoSuchObjectInstance /* 0x0112 == 274 */);
+      hasFailureReason_ = true;
+      
       return true;
     }
 
+    const std::string& GetSopClassUid() const
+    {
+      return sopClassUid_;
+    }
+    
+    const std::string& GetSopInstanceUid() const
+    {
+      return sopInstanceUid_;
+    }
+    
+    StorageCommitmentFailureReason GetFailureReason() const
+    {
+      if (hasFailureReason_)
+      {
+        return failureReason_;
+      }
+      else
+      {
+        throw OrthancException(ErrorCode_BadSequenceOfCalls);
+      }
+    }
+
     virtual void Serialize(Json::Value& target) const
     {
       target = Json::objectValue;
@@ -92,7 +165,7 @@
   };
 
   
-  class StorageCommitmentScpJob::AnswerCommand : public SetOfCommandsJob::ICommand
+  class StorageCommitmentScpJob::AnswerCommand : public StorageCommitmentCommand
   {
   private:
     StorageCommitmentScpJob&  that_;
@@ -111,6 +184,11 @@
       }
     }
 
+    virtual bool IsAnswer() const
+    {
+      return true;
+    }
+    
     virtual bool Execute()
     {
       that_.Answer();
@@ -128,11 +206,14 @@
   class StorageCommitmentScpJob::Unserializer : public SetOfCommandsJob::ICommandUnserializer
   {
   private:
-    StorageCommitmentScpJob&   that_;
+    StorageCommitmentScpJob&  that_;
+    ServerContext&            context_;
 
   public:
-    Unserializer(StorageCommitmentScpJob&  that) :
-      that_(that)
+    Unserializer(StorageCommitmentScpJob&  that,
+                 ServerContext& context) :
+      that_(that),
+      context_(context)
     {
       that_.ready_ = false;
     }
@@ -143,7 +224,7 @@
 
       if (type == LOOKUP)
       {
-        return new LookupCommand(that_,
+        return new LookupCommand(context_,
                                  SerializationToolbox::ReadString(source, SOP_CLASS_UID),
                                  SerializationToolbox::ReadString(source, SOP_INSTANCE_UID));
       }
@@ -159,60 +240,52 @@
   };
 
   
-  void StorageCommitmentScpJob::LookupInstance(const std::string& sopClassUid,
-                                               const std::string& sopInstanceUid)
-  {
-    bool success = false;
-      
-    try
+  void StorageCommitmentScpJob::Answer()
+  {   
+    LOG(INFO) << "  Storage commitment SCP job: Sending answer";
+
+    const size_t n = GetCommandsCount();
+
+    if (n == 0)
     {
-      std::vector<std::string> orthancId;
-      context_.GetIndex().LookupIdentifierExact(orthancId, ResourceType_Instance, DICOM_TAG_SOP_INSTANCE_UID, sopInstanceUid);
+      throw OrthancException(ErrorCode_InternalError);
+    }
+    
+    std::vector<std::string> sopClassUids, sopInstanceUids;
+    std::vector<StorageCommitmentFailureReason> failureReasons;
 
-      if (orthancId.size() == 1)
+    sopClassUids.reserve(n);
+    sopInstanceUids.reserve(n);
+    failureReasons.reserve(n);
+
+    for (size_t i = 0; i < n; i++)
+    {
+      const StorageCommitmentCommand& command = dynamic_cast<const StorageCommitmentCommand&>(GetCommand(i));
+
+      if (i == n - 1)
       {
-        std::string a, b;
+        if (!command.IsAnswer())
+        {
+          throw OrthancException(ErrorCode_InternalError);
+        }
+      }
+      else
+      {      
+        if (command.IsAnswer())
+        {
+          throw OrthancException(ErrorCode_InternalError);
+        }
 
-        // 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;
-        }
+        const LookupCommand& lookup = dynamic_cast<const LookupCommand&>(command);
+
+        sopClassUids.push_back(lookup.GetSopClassUid());
+        sopInstanceUids.push_back(lookup.GetSopInstanceUid());
+        failureReasons.push_back(lookup.GetFailureReason());
       }
     }
-    catch (OrthancException&)
-    {
-    }
-
-    LOG(INFO) << "  Storage commitment SCP job: " << (success ? "Success" : "Failure")
-              << " while looking for " << sopClassUid << " / " << sopInstanceUid;
-
-    if (success)
-    {
-      successSopClassUids_.push_back(sopClassUid);
-      successSopInstanceUids_.push_back(sopInstanceUid);
-    }
-    else
-    {
-      failedSopClassUids_.push_back(sopClassUid);
-      failedSopInstanceUids_.push_back(sopInstanceUid);
-    }
-  }
-
-    
-  void StorageCommitmentScpJob::Answer()
-  {
-    LOG(INFO) << "  Storage commitment SCP job: Sending answer";
       
     DicomUserConnection scu(calledAet_, remoteModality_);
-    scu.ReportStorageCommitment(transactionUid_, successSopClassUids_, successSopInstanceUids_,
-                                failedSopClassUids_, failedSopInstanceUids_);
+    scu.ReportStorageCommitment(transactionUid_, sopClassUids, sopInstanceUids, failureReasons);
   }
     
 
@@ -245,7 +318,7 @@
     }
     else
     {
-      AddCommand(new LookupCommand(*this, sopClassUid, sopInstanceUid));        
+      AddCommand(new LookupCommand(context_, sopClassUid, sopInstanceUid));        
     }
   }
     
@@ -266,19 +339,14 @@
   }
 
 
-
   StorageCommitmentScpJob::StorageCommitmentScpJob(ServerContext& context,
                                                    const Json::Value& serialized) :
-    SetOfCommandsJob(new Unserializer(*this), serialized),
+    SetOfCommandsJob(new Unserializer(*this, context), serialized),
     context_(context)
   {
     transactionUid_ = SerializationToolbox::ReadString(serialized, TRANSACTION_UID);
     remoteModality_ = RemoteModalityParameters(serialized[REMOTE_MODALITY]);
     calledAet_ = SerializationToolbox::ReadString(serialized, CALLED_AET);
-    SerializationToolbox::ReadListOfStrings(successSopClassUids_, serialized, SUCCESS_SOP_CLASS_UIDS);
-    SerializationToolbox::ReadListOfStrings(successSopInstanceUids_, serialized, SUCCESS_SOP_INSTANCE_UIDS);
-    SerializationToolbox::ReadListOfStrings(failedSopClassUids_, serialized, FAILED_SOP_CLASS_UIDS);
-    SerializationToolbox::ReadListOfStrings(failedSopInstanceUids_, serialized, FAILED_SOP_INSTANCE_UIDS);
   }
   
 
@@ -293,10 +361,6 @@
       target[TRANSACTION_UID] = transactionUid_;
       remoteModality_.Serialize(target[REMOTE_MODALITY], true /* force advanced format */);
       target[CALLED_AET] = calledAet_;
-      SerializationToolbox::WriteListOfStrings(target, successSopClassUids_, SUCCESS_SOP_CLASS_UIDS);
-      SerializationToolbox::WriteListOfStrings(target, successSopInstanceUids_, SUCCESS_SOP_INSTANCE_UIDS);
-      SerializationToolbox::WriteListOfStrings(target, failedSopClassUids_, FAILED_SOP_CLASS_UIDS);
-      SerializationToolbox::WriteListOfStrings(target, failedSopInstanceUids_, FAILED_SOP_INSTANCE_UIDS);
       return true;
     }
   }