changeset 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 cccd97333e3d
children 2d90dd30858c
files Core/DicomNetworking/DicomUserConnection.cpp Core/DicomNetworking/DicomUserConnection.h Core/Enumerations.h NEWS OrthancServer/OrthancRestApi/OrthancRestModalities.cpp OrthancServer/ServerJobs/StorageCommitmentScpJob.cpp OrthancServer/ServerJobs/StorageCommitmentScpJob.h
diffstat 7 files changed, 254 insertions(+), 124 deletions(-) [+]
line wrap: on
line diff
--- a/Core/DicomNetworking/DicomUserConnection.cpp	Mon Feb 10 10:37:10 2020 +0100
+++ b/Core/DicomNetworking/DicomUserConnection.cpp	Mon Feb 10 14:53:36 2020 +0100
@@ -1387,12 +1387,15 @@
 
   static void FillSopSequence(DcmDataset& dataset,
                               const DcmTagKey& tag,
-                              const std::list<std::string>& sopClassUids,
-                              const std::list<std::string>& sopInstanceUids,
-                              bool hasFailureReason,
-                              Uint16 failureReason)
+                              const std::vector<std::string>& sopClassUids,
+                              const std::vector<std::string>& sopInstanceUids,
+                              const std::vector<StorageCommitmentFailureReason>& failureReasons,
+                              bool hasFailureReasons)
   {
-    assert(sopClassUids.size() == sopInstanceUids.size());
+    assert(sopClassUids.size() == sopInstanceUids.size() &&
+           (hasFailureReasons ?
+            failureReasons.size() == sopClassUids.size() :
+            failureReasons.empty()));
 
     if (sopInstanceUids.empty())
     {
@@ -1404,27 +1407,17 @@
     }
     else
     {
-      std::list<std::string>::const_iterator currentClass = sopClassUids.begin();
-      std::list<std::string>::const_iterator currentInstance = sopInstanceUids.begin();
-
-      while (currentClass != sopClassUids.end())
+      for (size_t i = 0; i < sopClassUids.size(); i++)
       {
         std::auto_ptr<DcmItem> item(new DcmItem);
-        if (!item->putAndInsertString(DCM_ReferencedSOPClassUID, currentClass->c_str()).good() ||
-            !item->putAndInsertString(DCM_ReferencedSOPInstanceUID, currentInstance->c_str()).good() ||
-            (hasFailureReason &&
-             !item->putAndInsertUint16(DCM_FailureReason, failureReason).good()) ||
+        if (!item->putAndInsertString(DCM_ReferencedSOPClassUID, sopClassUids[i].c_str()).good() ||
+            !item->putAndInsertString(DCM_ReferencedSOPInstanceUID, sopInstanceUids[i].c_str()).good() ||
+            (hasFailureReasons &&
+             !item->putAndInsertUint16(DCM_FailureReason, failureReasons[i]).good()) ||
             !dataset.insertSequenceItem(tag, item.release()).good())
         {
           throw OrthancException(ErrorCode_InternalError);
         }
-
-        ++currentClass;
-        ++currentInstance;
-      }
-      
-      for (size_t i = 0; i < sopClassUids.size(); i++)
-      {
       }
     }
   }                              
@@ -1434,13 +1427,12 @@
 
   void DicomUserConnection::ReportStorageCommitment(
     const std::string& transactionUid,
-    const std::list<std::string>& successSopClassUids,
-    const std::list<std::string>& successSopInstanceUids,
-    const std::list<std::string>& failureSopClassUids,
-    const std::list<std::string>& failureSopInstanceUids)
+    const std::vector<std::string>& sopClassUids,
+    const std::vector<std::string>& sopInstanceUids,
+    const std::vector<StorageCommitmentFailureReason>& failureReasons)
   {
-    if (successSopClassUids.size() != successSopInstanceUids.size() ||
-        failureSopClassUids.size() != failureSopInstanceUids.size())
+    if (sopClassUids.size() != sopInstanceUids.size() ||
+        sopClassUids.size() != failureReasons.size())
     {
       throw OrthancException(ErrorCode_ParameterOutOfRange);
     }
@@ -1450,6 +1442,45 @@
       Close();
     }
 
+    std::vector<std::string> successSopClassUids, successSopInstanceUids, failedSopClassUids, failedSopInstanceUids;
+    std::vector<StorageCommitmentFailureReason> failedReasons;
+
+    successSopClassUids.reserve(sopClassUids.size());
+    successSopInstanceUids.reserve(sopClassUids.size());
+    failedSopClassUids.reserve(sopClassUids.size());
+    failedSopInstanceUids.reserve(sopClassUids.size());
+    failedReasons.reserve(sopClassUids.size());
+
+    for (size_t i = 0; i < sopClassUids.size(); i++)
+    {
+      switch (failureReasons[i])
+      {
+        case StorageCommitmentFailureReason_Success:
+          successSopClassUids.push_back(sopClassUids[i]);
+          successSopInstanceUids.push_back(sopInstanceUids[i]);
+          break;
+
+        case StorageCommitmentFailureReason_ProcessingFailure:
+        case StorageCommitmentFailureReason_NoSuchObjectInstance:
+        case StorageCommitmentFailureReason_ResourceLimitation:
+        case StorageCommitmentFailureReason_ReferencedSOPClassNotSupported:
+        case StorageCommitmentFailureReason_ClassInstanceConflict:
+        case StorageCommitmentFailureReason_DuplicateTransactionUID:
+          failedSopClassUids.push_back(sopClassUids[i]);
+          failedSopInstanceUids.push_back(sopInstanceUids[i]);
+          failedReasons.push_back(failureReasons[i]);
+          break;
+
+        default:
+        {
+          char buf[16];
+          sprintf(buf, "%04xH", failureReasons[i]);
+          throw OrthancException(ErrorCode_ParameterOutOfRange,
+                                 "Unsupported failure reason for storage commitment: " + std::string(buf));
+        }
+      }
+    }
+    
     try
     {
       OpenInternal(Mode_ReportStorageCommitment);
@@ -1470,7 +1501,7 @@
       LOG(INFO) << "Reporting modality \"" << remoteAet_
                 << "\" about storage commitment transaction: " << transactionUid
                 << " (" << successSopClassUids.size() << " successes, " 
-                << failureSopClassUids.size() << " failures)";
+                << failedSopClassUids.size() << " failures)";
       const DIC_US messageId = pimpl_->assoc_->nextMsgID++;
       
       {
@@ -1490,11 +1521,14 @@
           throw OrthancException(ErrorCode_InternalError);
         }
 
-        FillSopSequence(dataset, DCM_ReferencedSOPSequence, successSopClassUids,
-                        successSopInstanceUids, false, 0);
+        {
+          std::vector<StorageCommitmentFailureReason> empty;
+          FillSopSequence(dataset, DCM_ReferencedSOPSequence, successSopClassUids,
+                          successSopInstanceUids, empty, false);
+        }
 
         // http://dicom.nema.org/medical/dicom/2019a/output/chtml/part04/sect_J.3.3.html
-        if (failureSopClassUids.empty())
+        if (failedSopClassUids.empty())
         {
           content.EventTypeID = 1;  // "Storage Commitment Request Successful"
         }
@@ -1504,8 +1538,8 @@
 
           // Failure reason
           // http://dicom.nema.org/medical/dicom/2019a/output/chtml/part03/sect_C.14.html#sect_C.14.1.1
-          FillSopSequence(dataset, DCM_FailedSOPSequence, failureSopClassUids,
-                          failureSopInstanceUids, true, 0x0112 /* No such object instance == 274 */);
+          FillSopSequence(dataset, DCM_FailedSOPSequence, failedSopClassUids,
+                          failedSopInstanceUids, failedReasons, true);
         }
 
         int presID = ASC_findAcceptedPresentationContextID(
@@ -1574,8 +1608,8 @@
   
   void DicomUserConnection::RequestStorageCommitment(
     const std::string& transactionUid,
-    const std::list<std::string>& sopClassUids,
-    const std::list<std::string>& sopInstanceUids)
+    const std::vector<std::string>& sopClassUids,
+    const std::vector<std::string>& sopInstanceUids)
   {
     if (sopClassUids.size() != sopInstanceUids.size())
     {
@@ -1633,8 +1667,11 @@
           throw OrthancException(ErrorCode_InternalError);
         }
 
-        FillSopSequence(dataset, DCM_ReferencedSOPSequence, sopClassUids, sopInstanceUids, false, 0);
-
+        {
+          std::vector<StorageCommitmentFailureReason> empty;
+          FillSopSequence(dataset, DCM_ReferencedSOPSequence, sopClassUids, sopInstanceUids, empty, false);
+        }
+          
         int presID = ASC_findAcceptedPresentationContextID(
           pimpl_->assoc_, UID_StorageCommitmentPushModelSOPClass);
         if (presID == 0)
--- a/Core/DicomNetworking/DicomUserConnection.h	Mon Feb 10 10:37:10 2020 +0100
+++ b/Core/DicomNetworking/DicomUserConnection.h	Mon Feb 10 14:53:36 2020 +0100
@@ -228,15 +228,14 @@
 
     void ReportStorageCommitment(
       const std::string& transactionUid,
-      const std::list<std::string>& successSopClassUids,
-      const std::list<std::string>& successSopInstanceUids,
-      const std::list<std::string>& failureSopClassUids,
-      const std::list<std::string>& failureSopInstanceUids);      
+      const std::vector<std::string>& sopClassUids,
+      const std::vector<std::string>& sopInstanceUids,
+      const std::vector<StorageCommitmentFailureReason>& failureReasons);
 
     // transactionUid: To be generated by Toolbox::GenerateDicomPrivateUniqueIdentifier()
     void RequestStorageCommitment(
       const std::string& transactionUid,
-      const std::list<std::string>& sopClassUids,
-      const std::list<std::string>& sopInstanceUids);
+      const std::vector<std::string>& sopClassUids,
+      const std::vector<std::string>& sopInstanceUids);
   };
 }
--- a/Core/Enumerations.h	Mon Feb 10 10:37:10 2020 +0100
+++ b/Core/Enumerations.h	Mon Feb 10 14:53:36 2020 +0100
@@ -667,6 +667,36 @@
     JobStopReason_Retry
   };
 
+  
+  // http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.14.html#sect_C.14.1.1
+  enum StorageCommitmentFailureReason
+  {
+    StorageCommitmentFailureReason_Success = 0,
+
+    // A general failure in processing the operation was encountered
+    StorageCommitmentFailureReason_ProcessingFailure = 0x0110,
+
+    // One or more of the elements in the Referenced SOP Instance
+    // Sequence was not available
+    StorageCommitmentFailureReason_NoSuchObjectInstance = 0x0112,
+
+    // The SCP does not currently have enough resources to store the
+    // requested SOP Instance(s)
+    StorageCommitmentFailureReason_ResourceLimitation = 0x0213,
+
+    // Storage Commitment has been requested for a SOP Instance with a
+    // SOP Class that is not supported by the SCP
+    StorageCommitmentFailureReason_ReferencedSOPClassNotSupported = 0x0122,
+
+    // The SOP Class of an element in the Referenced SOP Instance
+    // Sequence did not correspond to the SOP class registered for
+    // this SOP Instance at the SCP
+    StorageCommitmentFailureReason_ClassInstanceConflict = 0x0119,
+
+    // The Transaction UID of the Storage Commitment Request is already in use
+    StorageCommitmentFailureReason_DuplicateTransactionUID = 0x0131    
+  };
+
 
   /**
    * WARNING: Do not change the explicit values in the enumerations
--- a/NEWS	Mon Feb 10 10:37:10 2020 +0100
+++ b/NEWS	Mon Feb 10 14:53:36 2020 +0100
@@ -1,6 +1,11 @@
 Pending changes in the mainline
 ===============================
 
+General
+-------
+
+* Support of DICOM storage commitment
+
 REST API
 --------
 
--- a/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp	Mon Feb 10 10:37:10 2020 +0100
+++ b/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp	Mon Feb 10 14:53:36 2020 +0100
@@ -1312,7 +1312,7 @@
       {
         DicomUserConnection scu(localAet, remote);
 
-        std::list<std::string> sopClassUids, sopInstanceUids;
+        std::vector<std::string> sopClassUids, sopInstanceUids;
         sopClassUids.push_back("a");
         sopInstanceUids.push_back("b");
         sopClassUids.push_back("1.2.840.10008.5.1.4.1.1.6.1");
--- 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;
     }
   }
--- a/OrthancServer/ServerJobs/StorageCommitmentScpJob.h	Mon Feb 10 10:37:10 2020 +0100
+++ b/OrthancServer/ServerJobs/StorageCommitmentScpJob.h	Mon Feb 10 14:53:36 2020 +0100
@@ -36,7 +36,7 @@
 #include "../../Core/DicomNetworking/RemoteModalityParameters.h"
 #include "../../Core/JobsEngine/SetOfCommandsJob.h"
 
-#include <list>
+#include <vector>
 
 namespace Orthanc
 {
@@ -45,7 +45,8 @@
   class StorageCommitmentScpJob : public SetOfCommandsJob
   {
   private:
-    class LookupCommand;    
+    class StorageCommitmentCommand;
+    class LookupCommand;
     class AnswerCommand;
     class Unserializer;
 
@@ -54,13 +55,7 @@
     std::string               transactionUid_;
     RemoteModalityParameters  remoteModality_;
     std::string               calledAet_;
-    std::list<std::string>    successSopClassUids_;
-    std::list<std::string>    successSopInstanceUids_;
-    std::list<std::string>    failedSopClassUids_;
-    std::list<std::string>    failedSopInstanceUids_;
 
-    void LookupInstance(const std::string& sopClassUid,
-                        const std::string& sopInstanceUid);
     void Answer();
     
   public: