changeset 2868:abce036683cd

sharing code within OrthancRestAnonymizeModify
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 08 Oct 2018 17:05:19 +0200
parents 251614c2edac
children 2bd87764709c
files OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp OrthancServer/OrthancRestApi/OrthancRestModalities.cpp OrthancServer/ServerJobs/ResourceModificationJob.cpp OrthancServer/ServerJobs/ResourceModificationJob.h UnitTestsSources/MultiThreadingTests.cpp
diffstat 5 files changed, 132 insertions(+), 242 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp	Mon Oct 08 16:08:51 2018 +0200
+++ b/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp	Mon Oct 08 17:05:19 2018 +0200
@@ -57,39 +57,14 @@
   }
 
 
-  static int GetPriority(const Json::Value& request)
-  {
-    static const char* PRIORITY = "Priority";
-    
-    if (request.isMember(PRIORITY))
-    {
-      if (request[PRIORITY].type() == Json::intValue)
-      {
-        return request[PRIORITY].asInt();
-      }
-      else
-      {
-        LOG(ERROR) << "Field \"" << PRIORITY << "\" of a modification request should be an integer";
-        throw OrthancException(ErrorCode_BadFileFormat);        
-      }
-    }
-    else
-    {
-      return 0;   // Default priority
-    }
-  }
-
-
-  static void ParseModifyRequest(DicomModification& target,
-                                 int& priority,
+  static void ParseModifyRequest(Json::Value& request,
+                                 DicomModification& target,
                                  const RestApiPostCall& call)
   {
     // curl http://localhost:8042/series/95a6e2bf-9296e2cc-bf614e2f-22b391ee-16e010e0/modify -X POST -d '{"Replace":{"InstitutionName":"My own clinic"},"Priority":9}'
 
-    Json::Value request;
     if (call.ParseJsonRequest(request))
     {
-      priority = GetPriority(request);
       target.ParseModifyRequest(request);
     }
     else
@@ -99,18 +74,15 @@
   }
 
 
-  static void ParseAnonymizationRequest(DicomModification& target,
-                                        int& priority,
+  static void ParseAnonymizationRequest(Json::Value& request,
+                                        DicomModification& target,
                                         RestApiPostCall& call)
   {
     // curl http://localhost:8042/instances/6e67da51-d119d6ae-c5667437-87b9a8a5-0f07c49f/anonymize -X POST -d '{"Replace":{"PatientName":"hello","0010-0020":"world"},"Keep":["StudyDescription", "SeriesDescription"],"KeepPrivateTags": true,"Remove":["Modality"]}' > Anonymized.dcm
 
-    Json::Value request;
     if (call.ParseJsonRequest(request) &&
         request.isObject())
     {
-      priority = GetPriority(request);
-
       bool patientNameReplaced;
       target.ParseAnonymizationRequest(patientNameReplaced, request);
 
@@ -145,49 +117,13 @@
   }
 
 
-
-  static void SubmitJob(std::auto_ptr<DicomModification>& modification,
-                        bool isAnonymization,
-                        ResourceType level,
-                        int priority,
-                        RestApiPostCall& call)
-  {
-    ServerContext& context = OrthancRestApi::GetContext(call);
-
-    std::auto_ptr<ResourceModificationJob> job(new ResourceModificationJob(context));
-    
-    boost::shared_ptr<ResourceModificationJob::Output> output(new ResourceModificationJob::Output(level));
-    job->SetModification(modification.release(), isAnonymization);
-    job->SetOutput(output);
-    job->SetOrigin(call);
-    job->SetDescription("REST API");
-
-    context.AddChildInstances(*job, call.GetUriComponent("id", ""));
-    
-    Json::Value publicContent;
-    if (context.GetJobsEngine().GetRegistry().SubmitAndWait
-        (publicContent, job.release(), priority))
-    {
-      Json::Value json;
-      if (output->Format(json))
-      {
-        call.GetOutput().AnswerJson(json);
-        return;
-      }
-    }
-
-    call.GetOutput().SignalError(HttpStatus_500_InternalServerError);
-  }
-
-
-
   static void ModifyInstance(RestApiPostCall& call)
   {
     DicomModification modification;
     modification.SetAllowManualIdentifiers(true);
 
-    int priority;
-    ParseModifyRequest(modification, priority, call);
+    Json::Value request;
+    ParseModifyRequest(request, modification, call);
 
     if (modification.IsReplaced(DICOM_TAG_PATIENT_ID))
     {
@@ -215,23 +151,45 @@
     DicomModification modification;
     modification.SetAllowManualIdentifiers(true);
 
-    int priority;
-    ParseAnonymizationRequest(modification, priority, call);
+    Json::Value request;
+    ParseAnonymizationRequest(request, modification, call);
 
     AnonymizeOrModifyInstance(modification, call);
   }
 
 
+  static void SubmitModificationJob(std::auto_ptr<DicomModification>& modification,
+                                    bool isAnonymization,
+                                    RestApiPostCall& call,
+                                    const Json::Value& body,
+                                    ResourceType level)
+  {
+    ServerContext& context = OrthancRestApi::GetContext(call);
+
+    std::auto_ptr<ResourceModificationJob> job(new ResourceModificationJob(context));
+    
+    job->SetModification(modification.release(), level, isAnonymization);
+    job->SetOrigin(call);
+    
+    context.AddChildInstances(*job, call.GetUriComponent("id", ""));
+
+    OrthancRestApi::GetApi(call).SubmitCommandsJob
+      (call, job.release(), true /* synchronous by default */, body);
+  }
+
+
   template <enum ResourceType resourceType>
   static void ModifyResource(RestApiPostCall& call)
   {
     std::auto_ptr<DicomModification> modification(new DicomModification);
 
-    int priority;
-    ParseModifyRequest(*modification, priority, call);
+    Json::Value body;
+    ParseModifyRequest(body, *modification, call);
 
     modification->SetLevel(resourceType);
-    SubmitJob(modification, false, resourceType, priority, call);
+
+    SubmitModificationJob(modification, false /* not an anonymization */,
+                          call, body, resourceType);
   }
 
 
@@ -240,10 +198,11 @@
   {
     std::auto_ptr<DicomModification> modification(new DicomModification);
 
-    int priority;
-    ParseAnonymizationRequest(*modification, priority, call);
+    Json::Value body;
+    ParseAnonymizationRequest(body, *modification, call);
 
-    SubmitJob(modification, true, resourceType, priority, call);
+    SubmitModificationJob(modification, true /* anonymization */,
+                          call, body, resourceType);
   }
 
 
--- a/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp	Mon Oct 08 16:08:51 2018 +0200
+++ b/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp	Mon Oct 08 17:05:19 2018 +0200
@@ -721,50 +721,6 @@
   }
 
 
-  static void SubmitJob(RestApiPostCall& call,
-                        const Json::Value& request,
-                        SetOfInstancesJob* jobRaw)
-  {
-    std::auto_ptr<SetOfInstancesJob> job(jobRaw);
-    
-    if (job.get() == NULL)
-    {
-      throw OrthancException(ErrorCode_NullPointer);
-    }
-    
-    ServerContext& context = OrthancRestApi::GetContext(call);
-
-    bool permissive = Toolbox::GetJsonBooleanField(request, "Permissive", false);
-    bool asynchronous = Toolbox::GetJsonBooleanField(request, "Asynchronous", false);
-    int priority = Toolbox::GetJsonIntegerField(request, "Priority", 0);
-
-    job->SetPermissive(permissive);
-    
-    Json::Value publicContent;
-
-    if (asynchronous)
-    {
-      // Asynchronous mode: Submit the job, but don't wait for its completion
-      std::string id;
-      context.GetJobsEngine().GetRegistry().Submit(id, job.release(), priority);
-
-      Json::Value v;
-      v["ID"] = id;
-      call.GetOutput().AnswerJson(v);
-    }
-    else if (context.GetJobsEngine().GetRegistry().SubmitAndWait
-             (publicContent, job.release(), priority))
-    {
-      // Synchronous mode: We have submitted and waited for completion
-      call.GetOutput().AnswerBuffer("{}", "application/json");
-    }
-    else
-    {
-      call.GetOutput().SignalError(HttpStatus_500_InternalServerError);
-    }
-  }
-
-
   static void DicomStore(RestApiPostCall& call)
   {
     ServerContext& context = OrthancRestApi::GetContext(call);
@@ -783,18 +739,16 @@
       int moveOriginatorID = Toolbox::GetJsonIntegerField
         (request, "MoveOriginatorID", 0 /* By default, not a C-MOVE */);
 
-      RemoteModalityParameters p = Configuration::GetModalityUsingSymbolicName(remote);
-
-      job->SetDescription("REST API");
       job->SetLocalAet(localAet);
-      job->SetRemoteModality(p);
+      job->SetRemoteModality(Configuration::GetModalityUsingSymbolicName(remote));
 
       if (moveOriginatorID != 0)
       {
         job->SetMoveOriginator(moveOriginatorAET, moveOriginatorID);
       }
 
-      SubmitJob(call, request, job.release());
+      OrthancRestApi::GetApi(call).SubmitCommandsJob
+        (call, job.release(), true /* synchronous by default */, request);
     }
   }
 
@@ -925,9 +879,9 @@
       WebServiceParameters peer;
       if (Configuration::GetOrthancPeer(peer, remote))
       {
-        job->SetDescription("REST API");
         job->SetPeer(peer);    
-        SubmitJob(call, request, job.release());
+        OrthancRestApi::GetApi(call).SubmitCommandsJob
+          (call, job.release(), true /* synchronous by default */, request);
       }
       else
       {
--- a/OrthancServer/ServerJobs/ResourceModificationJob.cpp	Mon Oct 08 16:08:51 2018 +0200
+++ b/OrthancServer/ServerJobs/ResourceModificationJob.cpp	Mon Oct 08 17:05:19 2018 +0200
@@ -39,88 +39,100 @@
 
 namespace Orthanc
 {
-  ResourceModificationJob::Output::Output(ResourceType  level) :
-    level_(level),
-    isFirst_(true)
+  class ResourceModificationJob::Output : public boost::noncopyable
   {
-    if (level_ != ResourceType_Patient &&
-        level_ != ResourceType_Study &&
-        level_ != ResourceType_Series)
+  private:
+    ResourceType  level_;
+    bool          isFirst_;
+    std::string   id_;
+    std::string   patientId_;
+
+  public:
+    Output(ResourceType level) :
+      level_(level),
+      isFirst_(true)
+    {
+      if (level_ != ResourceType_Patient &&
+          level_ != ResourceType_Study &&
+          level_ != ResourceType_Series)
+      {
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
+      }            
+    }
+
+    ResourceType GetLevel() const
     {
-      throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }            
-  }
+      return level_;
+    }
+    
+
+    void Update(DicomInstanceHasher& hasher)
+    {
+      if (isFirst_)
+      {
+        switch (level_)
+        {
+          case ResourceType_Series:
+            id_ = hasher.HashSeries();
+            break;
+
+          case ResourceType_Study:
+            id_ = hasher.HashStudy();
+            break;
+
+          case ResourceType_Patient:
+            id_ = hasher.HashPatient();
+            break;
+
+          default:
+            throw OrthancException(ErrorCode_InternalError);
+        }
+
+        patientId_ = hasher.HashPatient();
+        isFirst_ = false;
+      }
+    }
 
 
-  void ResourceModificationJob::Output::Update(DicomInstanceHasher& hasher)
-  {
-    boost::mutex::scoped_lock lock(mutex_);
-        
-    if (isFirst_)
+    bool Format(Json::Value& target)
     {
-      switch (level_)
+      if (isFirst_)
       {
-        case ResourceType_Series:
-          id_ = hasher.HashSeries();
-          break;
-
-        case ResourceType_Study:
-          id_ = hasher.HashStudy();
-          break;
-
-        case ResourceType_Patient:
-          id_ = hasher.HashPatient();
-          break;
-
-        default:
-          throw OrthancException(ErrorCode_InternalError);
+        return false;
       }
-
-      patientId_ = hasher.HashPatient();
-      isFirst_ = false;
+      else
+      {
+        target = Json::objectValue;
+        target["Type"] = EnumerationToString(level_);
+        target["ID"] = id_;
+        target["Path"] = GetBasePath(level_, id_);
+        target["PatientID"] = patientId_;
+        return true;
+      }
     }
-  }
-
-
-  bool ResourceModificationJob::Output::Format(Json::Value& target)
-  {
-    boost::mutex::scoped_lock lock(mutex_);
-        
-    if (isFirst_)
-    {
-      return false;
-    }
-    else
-    {
-      target = Json::objectValue;
-      target["Type"] = EnumerationToString(level_);
-      target["ID"] = id_;
-      target["Path"] = GetBasePath(level_, id_);
-      target["PatientID"] = patientId_;
-      return true;
-    }
-  }
 
   
-  bool ResourceModificationJob::Output::GetIdentifier(std::string& id)
-  {
-    boost::mutex::scoped_lock lock(mutex_);
-        
-    if (isFirst_)
+    bool GetIdentifier(std::string& id)
     {
-      return false;
+      if (isFirst_)
+      {
+        return false;
+      }
+      else
+      {
+        id = id_;
+        return true;
+      }
     }
-    else
-    {
-      id = id_;
-      return true;
-    }
-  }
+  };
+    
+
 
 
   bool ResourceModificationJob::HandleInstance(const std::string& instance)
   {
-    if (modification_.get() == NULL)
+    if (modification_.get() == NULL ||
+        output_.get() == NULL)
     {
       LOG(ERROR) << "No modification was provided for this job";
       throw OrthancException(ErrorCode_BadSequenceOfCalls);
@@ -204,14 +216,9 @@
       throw OrthancException(ErrorCode_CannotStoreInstance);
     }
 
-    // Sanity checks in debug mode
     assert(modifiedInstance == modifiedHasher.HashInstance());
 
-
-    if (output_.get() != NULL)
-    {
-      output_->Update(modifiedHasher);
-    }
+    output_->Update(modifiedHasher);
 
     return true;
   }
@@ -224,6 +231,7 @@
 
 
   void ResourceModificationJob::SetModification(DicomModification* modification,
+                                                ResourceType level,
                                                 bool isAnonymization)
   {
     if (modification == NULL)
@@ -237,24 +245,12 @@
     else
     {
       modification_.reset(modification);
+      output_.reset(new Output(level));
       isAnonymization_ = isAnonymization;
     }
   }
 
 
-  void ResourceModificationJob::SetOutput(boost::shared_ptr<Output>& output)
-  {
-    if (IsStarted())
-    {
-      throw OrthancException(ErrorCode_BadSequenceOfCalls);
-    }
-    else
-    {
-      output_ = output;
-    }
-  }
-
-  
   void ResourceModificationJob::SetOrigin(const DicomInstanceOrigin& origin)
   {
     if (IsStarted())
@@ -292,6 +288,11 @@
     SetOfInstancesJob::GetPublicContent(value);
 
     value["IsAnonymization"] = isAnonymization_;
+
+    if (output_.get() != NULL)
+    {
+      output_->Format(value);
+    }
   }
 
 
--- a/OrthancServer/ServerJobs/ResourceModificationJob.h	Mon Oct 08 16:08:51 2018 +0200
+++ b/OrthancServer/ServerJobs/ResourceModificationJob.h	Mon Oct 08 17:05:19 2018 +0200
@@ -40,32 +40,9 @@
 {
   class ResourceModificationJob : public SetOfInstancesJob
   {
-  public:
-    class Output : public boost::noncopyable
-    {
-    private:
-      boost::mutex  mutex_;
-      ResourceType  level_;
-      bool          isFirst_;
-      std::string   id_;
-      std::string   patientId_;
-
-    public:
-      Output(ResourceType  level);
-
-      ResourceType GetLevel() const
-      {
-        return level_;
-      }
-
-      void Update(DicomInstanceHasher& hasher);
-
-      bool Format(Json::Value& target);
-
-      bool GetIdentifier(std::string& id);
-    };
+  private:
+    class Output;
     
-  private:
     ServerContext&                    context_;
     std::auto_ptr<DicomModification>  modification_;
     boost::shared_ptr<Output>         output_;
@@ -88,10 +65,9 @@
                             const Json::Value& serialized);
 
     void SetModification(DicomModification* modification,   // Takes ownership
+                         ResourceType level,
                          bool isAnonymization);
 
-    void SetOutput(boost::shared_ptr<Output>& output);
-
     void SetOrigin(const DicomInstanceOrigin& origin);
 
     void SetOrigin(const RestApiCall& call);
--- a/UnitTestsSources/MultiThreadingTests.cpp	Mon Oct 08 16:08:51 2018 +0200
+++ b/UnitTestsSources/MultiThreadingTests.cpp	Mon Oct 08 17:05:19 2018 +0200
@@ -1548,7 +1548,7 @@
     modification->SetupAnonymization(DicomVersion_2008);    
 
     ResourceModificationJob job(GetContext());
-    job.SetModification(modification.release(), true);
+    job.SetModification(modification.release(), ResourceType_Patient, true);
     job.SetOrigin(DicomInstanceOrigin::FromLua());
     
     ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job));