changeset 1998:9b61701c35f2

New URI "/modalities/.../move" to issue C-Move SCU requests
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 25 May 2016 15:16:17 +0200
parents f9f2aa1cc594
children 364cc624eb65
files NEWS OrthancServer/DicomProtocol/DicomUserConnection.cpp OrthancServer/DicomProtocol/DicomUserConnection.h OrthancServer/FromDcmtkBridge.cpp OrthancServer/FromDcmtkBridge.h OrthancServer/OrthancRestApi/OrthancRestModalities.cpp
diffstat 6 files changed, 123 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Wed May 25 11:50:35 2016 +0200
+++ b/NEWS	Wed May 25 15:16:17 2016 +0200
@@ -34,7 +34,8 @@
 REST API
 --------
 
-* "MoveOriginatorID" can be specified for /modalities/.../store
+* New URI "/modalities/.../move" to issue C-Move SCU requests
+* "MoveOriginatorID" can be specified for "/modalities/.../store"
 
 Maintenance
 -----------
--- a/OrthancServer/DicomProtocol/DicomUserConnection.cpp	Wed May 25 11:50:35 2016 +0200
+++ b/OrthancServer/DicomProtocol/DicomUserConnection.cpp	Wed May 25 15:16:17 2016 +0200
@@ -995,16 +995,9 @@
 
 
   void DicomUserConnection::Move(const std::string& targetAet,
+                                 ResourceType level,
                                  const DicomMap& findResult)
   {
-    if (!findResult.HasTag(DICOM_TAG_QUERY_RETRIEVE_LEVEL))
-    {
-      throw OrthancException(ErrorCode_InternalError);
-    }
-
-    const std::string tmp = findResult.GetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL).GetContent();
-    ResourceType level = StringToResourceType(tmp.c_str());
-
     DicomMap move;
     switch (level)
     {
@@ -1035,6 +1028,21 @@
   }
 
 
+  void DicomUserConnection::Move(const std::string& targetAet,
+                                 const DicomMap& findResult)
+  {
+    if (!findResult.HasTag(DICOM_TAG_QUERY_RETRIEVE_LEVEL))
+    {
+      throw OrthancException(ErrorCode_InternalError);
+    }
+
+    const std::string tmp = findResult.GetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL).GetContent();
+    ResourceType level = StringToResourceType(tmp.c_str());
+
+    Move(targetAet, level, findResult);
+  }
+
+
   void DicomUserConnection::MovePatient(const std::string& targetAet,
                                         const std::string& patientId)
   {
--- a/OrthancServer/DicomProtocol/DicomUserConnection.h	Wed May 25 11:50:35 2016 +0200
+++ b/OrthancServer/DicomProtocol/DicomUserConnection.h	Wed May 25 15:16:17 2016 +0200
@@ -148,6 +148,10 @@
               const DicomMap& fields);
 
     void Move(const std::string& targetAet,
+              ResourceType level,
+              const DicomMap& findResult);
+
+    void Move(const std::string& targetAet,
               const DicomMap& findResult);
 
     void MovePatient(const std::string& targetAet,
--- a/OrthancServer/FromDcmtkBridge.cpp	Wed May 25 11:50:35 2016 +0200
+++ b/OrthancServer/FromDcmtkBridge.cpp	Wed May 25 15:16:17 2016 +0200
@@ -1735,4 +1735,30 @@
 
     return result.release();
   }
+
+
+  void FromDcmtkBridge::FromJson(DicomMap& target,
+                                 const Json::Value& source)
+  {
+    if (source.type() != Json::objectValue)
+    {
+      throw OrthancException(ErrorCode_BadFileFormat);
+    }
+
+    target.Clear();
+
+    Json::Value::Members members = source.getMemberNames();
+
+    for (size_t i = 0; i < members.size(); i++)
+    {
+      const Json::Value& value = source[members[i]];
+
+      if (value.type() != Json::stringValue)
+      {
+        throw OrthancException(ErrorCode_BadFileFormat);
+      }
+      
+      target.SetValue(ParseTag(members[i]), value.asString());
+    }
+  }
 }
--- a/OrthancServer/FromDcmtkBridge.h	Wed May 25 11:50:35 2016 +0200
+++ b/OrthancServer/FromDcmtkBridge.h	Wed May 25 15:16:17 2016 +0200
@@ -160,5 +160,8 @@
 
     static DcmFileFormat* LoadFromMemoryBuffer(const void* buffer,
                                                size_t size);
+
+    static void FromJson(DicomMap& values,
+                         const Json::Value& result);
   };
 }
--- a/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp	Wed May 25 11:50:35 2016 +0200
+++ b/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp	Wed May 25 15:16:17 2016 +0200
@@ -386,7 +386,7 @@
       std::auto_ptr<QueryRetrieveHandler>  handler(new QueryRetrieveHandler(context));
 
       handler->SetModality(call.GetUriComponent("id", ""));
-      handler->SetLevel(StringToResourceType(request["Level"].asString().c_str()));
+      handler->SetLevel(StringToResourceType(request["Level"].asCString()));
 
       if (request.isMember("Query"))
       {
@@ -745,6 +745,76 @@
 
 
   /***************************************************************************
+   * DICOM C-Move SCU
+   ***************************************************************************/
+  
+  static void DicomMove(RestApiPostCall& call)
+  {
+    ServerContext& context = OrthancRestApi::GetContext(call);
+
+    Json::Value request;
+
+    static const char* RESOURCES = "Resources";
+    static const char* LEVEL = "Level";
+
+    if (!call.ParseJsonRequest(request) ||
+        request.type() != Json::objectValue ||
+        !request.isMember(RESOURCES) ||
+        !request.isMember(LEVEL) ||
+        request[RESOURCES].type() != Json::arrayValue ||
+        request[LEVEL].type() != Json::stringValue)
+    {
+      throw OrthancException(ErrorCode_BadFileFormat);
+    }
+
+    ResourceType level = StringToResourceType(request["Level"].asCString());
+    
+    static const char* LOCAL_AET = "LocalAet";
+    std::string localAet = context.GetDefaultLocalApplicationEntityTitle();
+    if (request.isMember(LOCAL_AET))
+    {
+      if (request[LOCAL_AET].type() == Json::stringValue)
+      {
+        localAet = request[LOCAL_AET].asString();
+      }
+      else
+      {
+        throw OrthancException(ErrorCode_BadFileFormat);
+      }
+    }
+
+    static const char* TARGET_AET = "TargetAet";
+    std::string targetAet = context.GetDefaultLocalApplicationEntityTitle();
+    if (request.isMember(TARGET_AET))
+    {
+      if (request[TARGET_AET].type() == Json::stringValue)
+      {
+        targetAet = request[TARGET_AET].asString();
+      }
+      else
+      {
+        throw OrthancException(ErrorCode_BadFileFormat);
+      }
+    }
+
+    const RemoteModalityParameters source = Configuration::GetModalityUsingSymbolicName(call.GetUriComponent("id", ""));
+      
+    for (Json::Value::ArrayIndex i = 0; i < request[RESOURCES].size(); i++)
+    {
+      DicomMap resource;
+      FromDcmtkBridge::FromJson(resource, request[RESOURCES][i]);
+
+      ReusableDicomUserConnection::Locker locker(context.GetReusableDicomUserConnection(), localAet, source);
+      locker.GetConnection().Move(targetAet, level, resource);
+    }
+
+    // Move has succeeded
+    call.GetOutput().AnswerBuffer("{}", "application/json");
+  }
+
+
+
+  /***************************************************************************
    * Orthanc Peers => Store client
    ***************************************************************************/
 
@@ -936,6 +1006,7 @@
     Register("/modalities/{id}/find-instance", DicomFindInstance);
     Register("/modalities/{id}/find", DicomFind);
     Register("/modalities/{id}/store", DicomStore);
+    Register("/modalities/{id}/move", DicomMove);
 
     // For Query/Retrieve
     Register("/modalities/{id}/query", DicomQuery);