changeset 613:60d90e48e809 find-move-scp

query/retrieve
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 18 Oct 2013 17:27:26 +0200
parents fdd5f7f9c4d7
children f27923072afd
files OrthancServer/Internals/MoveScp.cpp OrthancServer/OrthancInitialization.cpp OrthancServer/OrthancInitialization.h OrthancServer/OrthancRestApi.cpp OrthancServer/main.cpp
diffstat 5 files changed, 222 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancServer/Internals/MoveScp.cpp	Fri Oct 18 14:17:51 2013 +0200
+++ b/OrthancServer/Internals/MoveScp.cpp	Fri Oct 18 17:27:26 2013 +0200
@@ -82,6 +82,13 @@
         try
         {
           data.iterator_.reset(data.handler_->Handle(data.target_, data.input_));
+          if (data.iterator_.get() == NULL)
+          {
+            // Internal error!
+            response->DimseStatus = STATUS_MOVE_Failed_UnableToProcess;
+            return;
+          }
+
           data.subOperationCount_ = data.iterator_->GetSubOperationCount();
           data.failureCount_ = 0;
           data.warningCount_ = 0;
--- a/OrthancServer/OrthancInitialization.cpp	Fri Oct 18 14:17:51 2013 +0200
+++ b/OrthancServer/OrthancInitialization.cpp	Fri Oct 18 17:27:26 2013 +0200
@@ -464,4 +464,69 @@
       target.push_back(lst[i].asString());
     }    
   }
+
+
+  void ConnectToModalityUsingSymbolicName(DicomUserConnection& connection,
+                                          const std::string& name)
+  {
+    std::string aet, address;
+    int port;
+    ModalityManufacturer manufacturer;
+    GetDicomModality(name, aet, address, port, manufacturer);
+
+    LOG(WARNING) << "Connecting to remote DICOM modality: AET=" << aet << ", address=" << address << ", port=" << port;
+
+    connection.SetLocalApplicationEntityTitle(GetGlobalStringParameter("DicomAet", "ORTHANC"));
+    connection.SetDistantApplicationEntityTitle(aet);
+    connection.SetDistantHost(address);
+    connection.SetDistantPort(port);
+    connection.SetDistantManufacturer(manufacturer);
+    connection.Open();
+  }
+
+
+  void ConnectToModalityUsingAETitle(DicomUserConnection& connection,
+                                     const std::string& aet)
+  {
+    std::set<std::string> modalities;
+    GetListOfDicomModalities(modalities);
+
+    std::string address;
+    int port;
+    ModalityManufacturer manufacturer;
+    bool found = false;
+
+    for (std::set<std::string>::const_iterator 
+           it = modalities.begin(); it != modalities.end(); it++)
+    {
+      try
+      {
+        std::string thisAet;
+        GetDicomModality(*it, thisAet, address, port, manufacturer);
+        
+        if (aet == thisAet)
+        {
+          found = true;
+          break;
+        }
+      }
+      catch (OrthancException&)
+      {
+      }
+    }
+
+    if (!found)
+    {
+      throw OrthancException("Unknown modality: " + aet);
+    }
+
+    LOG(WARNING) << "Connecting to remote DICOM modality: AET=" << aet << ", address=" << address << ", port=" << port;
+
+    connection.SetLocalApplicationEntityTitle(GetGlobalStringParameter("DicomAet", "ORTHANC"));
+    connection.SetDistantApplicationEntityTitle(aet);
+    connection.SetDistantHost(address);
+    connection.SetDistantPort(port);
+    connection.SetDistantManufacturer(manufacturer);
+    connection.Open();
+  }
 }
--- a/OrthancServer/OrthancInitialization.h	Fri Oct 18 14:17:51 2013 +0200
+++ b/OrthancServer/OrthancInitialization.h	Fri Oct 18 17:27:26 2013 +0200
@@ -37,6 +37,7 @@
 #include <json/json.h>
 #include <stdint.h>
 #include "../Core/HttpServer/MongooseServer.h"
+#include "DicomProtocol/DicomUserConnection.h"
 #include "ServerEnumerations.h"
 
 namespace Orthanc
@@ -78,4 +79,10 @@
 
   void GetGlobalListOfStringsParameter(std::list<std::string>& target,
                                        const std::string& key);
+
+  void ConnectToModalityUsingSymbolicName(DicomUserConnection& connection,
+                                          const std::string& name);
+
+  void ConnectToModalityUsingAETitle(DicomUserConnection& connection,
+                                     const std::string& aet);
 }
--- a/OrthancServer/OrthancRestApi.cpp	Fri Oct 18 14:17:51 2013 +0200
+++ b/OrthancServer/OrthancRestApi.cpp	Fri Oct 18 17:27:26 2013 +0200
@@ -71,21 +71,6 @@
 
   // DICOM SCU ----------------------------------------------------------------
 
-  static void ConnectToModality(DicomUserConnection& connection,
-                                const std::string& name)
-  {
-    std::string aet, address;
-    int port;
-    ModalityManufacturer manufacturer;
-    GetDicomModality(name, aet, address, port, manufacturer);
-    connection.SetLocalApplicationEntityTitle(GetGlobalStringParameter("DicomAet", "ORTHANC"));
-    connection.SetDistantApplicationEntityTitle(aet);
-    connection.SetDistantHost(address);
-    connection.SetDistantPort(port);
-    connection.SetDistantManufacturer(manufacturer);
-    connection.Open();
-  }
-
   static bool MergeQueryAndTemplate(DicomMap& result,
                                     const std::string& postData)
   {
@@ -118,7 +103,7 @@
     }
 
     DicomUserConnection connection;
-    ConnectToModality(connection, call.GetUriComponent("id", ""));
+    ConnectToModalityUsingSymbolicName(connection, call.GetUriComponent("id", ""));
 
     DicomFindAnswers answers;
     connection.FindPatient(answers, m);
@@ -144,7 +129,7 @@
     }        
       
     DicomUserConnection connection;
-    ConnectToModality(connection, call.GetUriComponent("id", ""));
+    ConnectToModalityUsingSymbolicName(connection, call.GetUriComponent("id", ""));
   
     DicomFindAnswers answers;
     connection.FindStudy(answers, m);
@@ -171,7 +156,7 @@
     }        
          
     DicomUserConnection connection;
-    ConnectToModality(connection, call.GetUriComponent("id", ""));
+    ConnectToModalityUsingSymbolicName(connection, call.GetUriComponent("id", ""));
   
     DicomFindAnswers answers;
     connection.FindSeries(answers, m);
@@ -199,7 +184,7 @@
     }        
          
     DicomUserConnection connection;
-    ConnectToModality(connection, call.GetUriComponent("id", ""));
+    ConnectToModalityUsingSymbolicName(connection, call.GetUriComponent("id", ""));
   
     DicomFindAnswers answers;
     connection.FindInstance(answers, m);
@@ -219,7 +204,7 @@
     }
  
     DicomUserConnection connection;
-    ConnectToModality(connection, call.GetUriComponent("id", ""));
+    ConnectToModalityUsingSymbolicName(connection, call.GetUriComponent("id", ""));
   
     DicomFindAnswers patients;
     connection.FindPatient(patients, m);
@@ -350,7 +335,7 @@
     }
 
     DicomUserConnection connection;
-    ConnectToModality(connection, remote);
+    ConnectToModalityUsingSymbolicName(connection, remote);
 
     for (std::list<std::string>::const_iterator 
            it = instances.begin(); it != instances.end(); it++)
--- a/OrthancServer/main.cpp	Fri Oct 18 14:17:51 2013 +0200
+++ b/OrthancServer/main.cpp	Fri Oct 18 17:27:26 2013 +0200
@@ -41,6 +41,7 @@
 #include "../Core/Lua/LuaFunctionCall.h"
 #include "../Core/DicomFormat/DicomArray.h"
 #include "DicomProtocol/DicomServer.h"
+#include "DicomProtocol/DicomUserConnection.h"
 #include "OrthancInitialization.h"
 #include "ServerContext.h"
 #include "OrthancFindRequestHandler.h"
@@ -49,13 +50,13 @@
 
 
 
-class MyStoreRequestHandler : public IStoreRequestHandler
+class OrthancStoreRequestHandler : public IStoreRequestHandler
 {
 private:
   ServerContext& server_;
 
 public:
-  MyStoreRequestHandler(ServerContext& context) :
+  OrthancStoreRequestHandler(ServerContext& context) :
     server_(context)
   {
   }
@@ -73,13 +74,92 @@
 };
 
 
-class MyMoveRequestHandler : public IMoveRequestHandler
+
+class OrthancMoveRequestIterator : public IMoveRequestIterator
+{
+private:
+  ServerContext& context_;
+  std::vector<std::string> instances_;
+  DicomUserConnection connection_;
+  size_t position_;
+
+public:
+  OrthancMoveRequestIterator(ServerContext& context,
+                             const std::string& target,
+                             const std::string& publicId) :
+    context_(context),
+    position_(0)
+  {
+    LOG(INFO) << "Sending resource " << publicId << " to modality \"" << target << "\"";
+
+    std::list<std::string> tmp;
+    context_.GetIndex().GetChildInstances(tmp, publicId);
+
+    instances_.reserve(tmp.size());
+    for (std::list<std::string>::iterator it = tmp.begin(); it != tmp.end(); it++)
+    {
+      instances_.push_back(*it);
+    }
+    
+    ConnectToModalityUsingAETitle(connection_, target);
+  }
+
+  virtual unsigned int GetSubOperationCount() const
+  {
+    return instances_.size();
+  }
+
+  virtual Status DoNext()
+  {
+    if (position_ >= instances_.size())
+    {
+      return Status_Failure;
+    }
+
+    const std::string& id = instances_[position_++];
+
+    std::string dicom;
+    context_.ReadFile(dicom, id, FileContentType_Dicom);
+    connection_.Store(dicom);
+
+    return Status_Success;
+  }
+};
+
+
+
+class OrthancMoveRequestHandler : public IMoveRequestHandler
 {
 private:
   ServerContext& context_;
 
+  bool LookupResource(std::string& publicId,
+                      DicomTag tag,
+                      const DicomMap& input)
+  {
+    if (!input.HasTag(tag))
+    {
+      return false;
+    }
+
+    std::string value = input.GetValue(tag).AsString();
+
+    std::list<std::string> ids;
+    context_.GetIndex().LookupTagValue(ids, tag, value);
+
+    if (ids.size() != 1)
+    {
+      return false;
+    }
+    else
+    {
+      publicId = ids.front();
+      return true;
+    }
+  }
+
 public:
-  MyMoveRequestHandler(ServerContext& context) :
+  OrthancMoveRequestHandler(ServerContext& context) :
     context_(context)
   {
   }
@@ -88,8 +168,57 @@
   virtual IMoveRequestIterator* Handle(const std::string& target,
                                        const DicomMap& input)
   {
-    LOG(WARNING) << "Move-SCU request received";
-    return NULL;
+    LOG(WARNING) << "Move-SCU request received for AET \"" << target << "\"";
+
+
+    /**
+     * Retrieve the query level.
+     **/
+
+    const DicomValue* levelTmp = input.TestAndGetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL);
+    if (levelTmp == NULL) 
+    {
+      throw OrthancException(ErrorCode_BadRequest);
+    }
+
+    ResourceType level = StringToResourceType(levelTmp->AsString().c_str());
+
+
+    /**
+     * Lookup for the resource to be sent.
+     **/
+
+    bool ok;
+    std::string publicId;
+
+    switch (level)
+    {
+      case ResourceType_Patient:
+        ok = LookupResource(publicId, DICOM_TAG_PATIENT_ID, input);
+        break;
+
+      case ResourceType_Study:
+        ok = LookupResource(publicId, DICOM_TAG_STUDY_INSTANCE_UID, input);
+        break;
+
+      case ResourceType_Series:
+        ok = LookupResource(publicId, DICOM_TAG_SERIES_INSTANCE_UID, input);
+        break;
+
+      case ResourceType_Instance:
+        ok = LookupResource(publicId, DICOM_TAG_SOP_INSTANCE_UID, input);
+        break;
+
+      default:
+        ok = false;
+    }
+
+    if (!ok)
+    {
+      throw OrthancException(ErrorCode_BadRequest);
+    }
+
+    return new OrthancMoveRequestIterator(context_, target, publicId);
   }
 };
 
@@ -109,7 +238,7 @@
 
   virtual IStoreRequestHandler* ConstructStoreRequestHandler()
   {
-    return new MyStoreRequestHandler(context_);
+    return new OrthancStoreRequestHandler(context_);
   }
 
   virtual IFindRequestHandler* ConstructFindRequestHandler()
@@ -119,7 +248,7 @@
 
   virtual IMoveRequestHandler* ConstructMoveRequestHandler()
   {
-    return new MyMoveRequestHandler(context_);
+    return new OrthancMoveRequestHandler(context_);
   }
 
   void Done()