changeset 3941:771dbd9eb3bd transcoding

class CleaningInstancesJob to share cleaning code by merge/split jobs
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 18 May 2020 18:20:19 +0200
parents 3661e2a72482
children 5b882ad2ffd0
files CMakeLists.txt OrthancServer/ServerContext.cpp OrthancServer/ServerJobs/CleaningInstancesJob.cpp OrthancServer/ServerJobs/CleaningInstancesJob.h OrthancServer/ServerJobs/MergeStudyJob.cpp OrthancServer/ServerJobs/MergeStudyJob.h OrthancServer/ServerJobs/SplitStudyJob.cpp OrthancServer/ServerJobs/SplitStudyJob.h
diffstat 8 files changed, 232 insertions(+), 119 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Mon May 18 17:41:05 2020 +0200
+++ b/CMakeLists.txt	Mon May 18 18:20:19 2020 +0200
@@ -90,6 +90,7 @@
   OrthancServer/ServerEnumerations.cpp
   OrthancServer/ServerIndex.cpp
   OrthancServer/ServerJobs/ArchiveJob.cpp
+  OrthancServer/ServerJobs/CleaningInstancesJob.cpp
   OrthancServer/ServerJobs/DicomModalityStoreJob.cpp
   OrthancServer/ServerJobs/DicomMoveScuJob.cpp
   OrthancServer/ServerJobs/LuaJobManager.cpp
--- a/OrthancServer/ServerContext.cpp	Mon May 18 17:41:05 2020 +0200
+++ b/OrthancServer/ServerContext.cpp	Mon May 18 18:20:19 2020 +0200
@@ -295,7 +295,7 @@
         }
         else
         {
-          isIngestTranscoding_ = true;
+          isIngestTranscoding_ = false;
           LOG(INFO) << "Automated transcoding of incoming DICOM instances is disabled";
         }
       }
@@ -545,7 +545,7 @@
   {
     if (!isIngestTranscoding_)
     {
-      // No automated transcoding
+      // No automated transcoding. This was the only path in Orthanc <= 1.6.1.
       return StoreAfterTranscoding(resultPublicId, dicom, mode);
     }
     else
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancServer/ServerJobs/CleaningInstancesJob.cpp	Mon May 18 18:20:19 2020 +0200
@@ -0,0 +1,120 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "CleaningInstancesJob.h"
+
+#include "../../Core/SerializationToolbox.h"
+#include "../ServerContext.h"
+
+
+namespace Orthanc
+{
+  bool CleaningInstancesJob::HandleTrailingStep()
+  {
+    if (!keepSource_)
+    {
+      const size_t n = GetInstancesCount();
+
+      for (size_t i = 0; i < n; i++)
+      {
+        Json::Value tmp;
+        context_.DeleteResource(tmp, GetInstance(i), ResourceType_Instance);
+      }
+    }
+
+    return true;
+  }
+
+  
+  void CleaningInstancesJob::SetKeepSource(bool keep)
+  {
+    if (IsStarted())
+    {
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+
+    keepSource_ = keep;
+  }
+
+
+  static const char* KEEP_SOURCE = "KeepSource";
+
+
+  CleaningInstancesJob::CleaningInstancesJob(ServerContext& context,
+                                             const Json::Value& serialized,
+                                             bool defaultKeepSource) :
+    SetOfInstancesJob(serialized),  // (*)
+    context_(context)
+  {
+    if (!HasTrailingStep())
+    {
+      // Should have been set by (*)
+      throw OrthancException(ErrorCode_InternalError);
+    }
+
+    if (serialized.isMember(KEEP_SOURCE))
+    {
+      keepSource_ = SerializationToolbox::ReadBoolean(serialized, KEEP_SOURCE);
+    }
+    else
+    {
+      keepSource_ = defaultKeepSource;
+    }
+  }
+
+  
+  bool CleaningInstancesJob::Serialize(Json::Value& target)
+  {
+    if (!SetOfInstancesJob::Serialize(target))
+    {
+      return false;
+    }
+    else
+    {
+      target[KEEP_SOURCE] = keepSource_;
+      return true;
+    }
+  }
+
+
+  void CleaningInstancesJob::Start()
+  {
+    if (!HasTrailingStep())
+    {
+      throw OrthancException(ErrorCode_BadSequenceOfCalls,
+                             "AddTrailingStep() should have been called before submitting the job");
+    }
+
+    SetOfInstancesJob::Start();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancServer/ServerJobs/CleaningInstancesJob.h	Mon May 18 18:20:19 2020 +0200
@@ -0,0 +1,79 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2020 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "../../Core/JobsEngine/SetOfInstancesJob.h"
+
+namespace Orthanc
+{
+  class ServerContext;
+  
+  class CleaningInstancesJob : public SetOfInstancesJob
+  {
+  private:
+    ServerContext&  context_;
+    bool            keepSource_;
+    
+  protected:
+    virtual bool HandleTrailingStep();
+    
+  public:
+    CleaningInstancesJob(ServerContext& context,
+                         bool keepSource) :
+      context_(context),
+      keepSource_(keepSource)
+    {
+    }
+
+    CleaningInstancesJob(ServerContext& context,
+                         const Json::Value& serialized,
+                         bool defaultKeepSource);
+
+    ServerContext& GetContext() const
+    {
+      return context_;
+    }
+    
+    bool IsKeepSource() const
+    {
+      return keepSource_;
+    }
+    
+    void SetKeepSource(bool keep);
+
+    virtual bool Serialize(Json::Value& target);
+
+    virtual void Start();
+  };
+}
--- a/OrthancServer/ServerJobs/MergeStudyJob.cpp	Mon May 18 17:41:05 2020 +0200
+++ b/OrthancServer/ServerJobs/MergeStudyJob.cpp	Mon May 18 18:20:19 2020 +0200
@@ -48,7 +48,7 @@
 
     // Add all the instances of the series as to be processed
     std::list<std::string> instances;
-    context_.GetIndex().GetChildren(instances, series);
+    GetContext().GetIndex().GetChildren(instances, series);
 
     for (std::list<std::string>::const_iterator
            it = instances.begin(); it != instances.end(); ++it)
@@ -68,7 +68,7 @@
     else
     {
       std::list<std::string> series;
-      context_.GetIndex().GetChildren(series, study);
+      GetContext().GetIndex().GetChildren(series, study);
 
       for (std::list<std::string>::const_iterator
              it = series.begin(); it != series.end(); ++it)
@@ -95,7 +95,7 @@
 
     try
     {
-      ServerContext::DicomCacheLocker locker(context_, instance);
+      ServerContext::DicomCacheLocker locker(GetContext(), instance);
       modified.reset(locker.GetDicom().Clone(true));
     }
     catch (OrthancException&)
@@ -151,7 +151,7 @@
     toStore.SetParsedDicomFile(*modified);
 
     std::string modifiedInstance;
-    if (context_.Store(modifiedInstance, toStore,
+    if (GetContext().Store(modifiedInstance, toStore,
                        StoreInstanceMode_Default) != StoreStatus_Success)
     {
       LOG(ERROR) << "Error while storing a modified instance " << instance;
@@ -162,27 +162,9 @@
   }
 
   
-  bool MergeStudyJob::HandleTrailingStep()
-  {
-    if (!keepSource_)
-    {
-      const size_t n = GetInstancesCount();
-
-      for (size_t i = 0; i < n; i++)
-      {
-        Json::Value tmp;
-        context_.DeleteResource(tmp, GetInstance(i), ResourceType_Instance);
-      }
-    }
-
-    return true;
-  }
-
-  
   MergeStudyJob::MergeStudyJob(ServerContext& context,
                                const std::string& targetStudy) :
-    context_(context),
-    keepSource_(false),
+    CleaningInstancesJob(context, false /* by default, remove source instances */),
     targetStudy_(targetStudy)
   {
     /**
@@ -191,7 +173,7 @@
     
     ResourceType type;
 
-    if (!context_.GetIndex().LookupResourceType(type, targetStudy) ||
+    if (!GetContext().GetIndex().LookupResourceType(type, targetStudy) ||
         type != ResourceType_Study)
     {
       throw OrthancException(ErrorCode_UnknownResource,
@@ -208,7 +190,7 @@
     DicomTag::AddTagsForModule(removals_, DicomModule_Study);
     
     std::list<std::string> instances;
-    context_.GetIndex().GetChildInstances(instances, targetStudy);
+    GetContext().GetIndex().GetChildInstances(instances, targetStudy);
     
     if (instances.empty())
     {
@@ -218,7 +200,7 @@
     DicomMap dicom;
 
     {
-      ServerContext::DicomCacheLocker locker(context_, instances.front());
+      ServerContext::DicomCacheLocker locker(GetContext(), instances.front());
       locker.GetDicom().ExtractDicomSummary(dicom);
     }
 
@@ -266,7 +248,7 @@
     {
       throw OrthancException(ErrorCode_BadSequenceOfCalls);
     }
-    else if (!context_.GetIndex().LookupResourceType(level, studyOrSeries))
+    else if (!GetContext().GetIndex().LookupResourceType(level, studyOrSeries))
     {
       throw OrthancException(ErrorCode_UnknownResource,
                              "Cannot find this resource: " + studyOrSeries);
@@ -301,7 +283,7 @@
     {
       throw OrthancException(ErrorCode_BadSequenceOfCalls);
     }
-    else if (!context_.GetIndex().LookupParent(parent, series, ResourceType_Study))
+    else if (!GetContext().GetIndex().LookupParent(parent, series, ResourceType_Study))
     {
       throw OrthancException(ErrorCode_UnknownResource,
                              "This resource is not a series: " + series);
@@ -327,7 +309,7 @@
     {
       throw OrthancException(ErrorCode_BadSequenceOfCalls);
     }
-    else if (!context_.GetIndex().LookupResourceType(actualLevel, study) ||
+    else if (!GetContext().GetIndex().LookupResourceType(actualLevel, study) ||
              actualLevel != ResourceType_Study)
     {
       throw OrthancException(ErrorCode_UnknownResource,
@@ -340,25 +322,13 @@
   }
 
 
-  void MergeStudyJob::SetKeepSource(bool keep)
-  {
-    if (IsStarted())
-    {
-      throw OrthancException(ErrorCode_BadSequenceOfCalls);
-    }
-
-    keepSource_ = keep;
-  }
-
-
   void MergeStudyJob::GetPublicContent(Json::Value& value)
   {
-    SetOfInstancesJob::GetPublicContent(value);
+    CleaningInstancesJob::GetPublicContent(value);
     value["TargetStudy"] = targetStudy_;
   }
 
 
-  static const char* KEEP_SOURCE = "KeepSource";
   static const char* TARGET_STUDY = "TargetStudy";
   static const char* REPLACEMENTS = "Replacements";
   static const char* REMOVALS = "Removals";
@@ -368,8 +338,8 @@
 
   MergeStudyJob::MergeStudyJob(ServerContext& context,
                                const Json::Value& serialized) :
-    SetOfInstancesJob(serialized),  // (*)
-    context_(context)
+    CleaningInstancesJob(context, serialized,
+                         false /* by default, remove source instances */)  // (*)
   {
     if (!HasTrailingStep())
     {
@@ -377,7 +347,6 @@
       throw OrthancException(ErrorCode_InternalError);
     }
 
-    keepSource_ = SerializationToolbox::ReadBoolean(serialized, KEEP_SOURCE);
     targetStudy_ = SerializationToolbox::ReadString(serialized, TARGET_STUDY);
     SerializationToolbox::ReadMapOfTags(replacements_, serialized, REPLACEMENTS);
     SerializationToolbox::ReadSetOfTags(removals_, serialized, REMOVALS);
@@ -388,13 +357,12 @@
   
   bool MergeStudyJob::Serialize(Json::Value& target)
   {
-    if (!SetOfInstancesJob::Serialize(target))
+    if (!CleaningInstancesJob::Serialize(target))
     {
       return false;
     }
     else
     {
-      target[KEEP_SOURCE] = keepSource_;
       target[TARGET_STUDY] = targetStudy_;
       SerializationToolbox::WriteMapOfTags(target, replacements_, REPLACEMENTS);
       SerializationToolbox::WriteSetOfTags(target, removals_, REMOVALS);
--- a/OrthancServer/ServerJobs/MergeStudyJob.h	Mon May 18 17:41:05 2020 +0200
+++ b/OrthancServer/ServerJobs/MergeStudyJob.h	Mon May 18 18:20:19 2020 +0200
@@ -34,22 +34,20 @@
 #pragma once
 
 #include "../../Core/DicomFormat/DicomMap.h"
-#include "../../Core/JobsEngine/SetOfInstancesJob.h"
 #include "../DicomInstanceOrigin.h"
+#include "CleaningInstancesJob.h"
 
 namespace Orthanc
 {
   class ServerContext;
   
-  class MergeStudyJob : public SetOfInstancesJob
+  class MergeStudyJob : public CleaningInstancesJob
   {
   private:
     typedef std::map<std::string, std::string>  SeriesUidMap;
     typedef std::map<DicomTag, std::string>     Replacements;
     
     
-    ServerContext&         context_;
-    bool                   keepSource_;
     std::string            targetStudy_;
     Replacements           replacements_;
     std::set<DicomTag>     removals_;
@@ -61,12 +59,9 @@
 
     void AddSourceStudyInternal(const std::string& study);
 
-
   protected:
     virtual bool HandleInstance(const std::string& instance);
 
-    virtual bool HandleTrailingStep();
-    
   public:
     MergeStudyJob(ServerContext& context,
                   const std::string& targetStudy);
@@ -85,13 +80,6 @@
 
     void AddSourceSeries(const std::string& series);
 
-    bool IsKeepSource() const
-    {
-      return keepSource_;
-    }
-    
-    void SetKeepSource(bool keep);
-
     void SetOrigin(const DicomInstanceOrigin& origin);
 
     void SetOrigin(const RestApiCall& call);
--- a/OrthancServer/ServerJobs/SplitStudyJob.cpp	Mon May 18 17:41:05 2020 +0200
+++ b/OrthancServer/ServerJobs/SplitStudyJob.cpp	Mon May 18 18:20:19 2020 +0200
@@ -81,7 +81,7 @@
 
     try
     {
-      ServerContext::DicomCacheLocker locker(context_, instance);
+      ServerContext::DicomCacheLocker locker(GetContext(), instance);
       modified.reset(locker.GetDicom().Clone(true));
     }
     catch (OrthancException&)
@@ -144,8 +144,8 @@
     toStore.SetParsedDicomFile(*modified);
 
     std::string modifiedInstance;
-    if (context_.Store(modifiedInstance, toStore,
-                       StoreInstanceMode_Default) != StoreStatus_Success)
+    if (GetContext().Store(modifiedInstance, toStore,
+                           StoreInstanceMode_Default) != StoreStatus_Success)
     {
       LOG(ERROR) << "Error while storing a modified instance " << instance;
       return false;
@@ -155,27 +155,9 @@
   }
 
   
-  bool SplitStudyJob::HandleTrailingStep()
-  {
-    if (!keepSource_)
-    {
-      const size_t n = GetInstancesCount();
-
-      for (size_t i = 0; i < n; i++)
-      {
-        Json::Value tmp;
-        context_.DeleteResource(tmp, GetInstance(i), ResourceType_Instance);
-      }
-    }
-
-    return true;
-  }
-
-  
   SplitStudyJob::SplitStudyJob(ServerContext& context,
                                const std::string& sourceStudy) :
-    context_(context),
-    keepSource_(false),
+    CleaningInstancesJob(context, false /* by default, remove source instances */),
     sourceStudy_(sourceStudy),
     targetStudyUid_(FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Study))
   {
@@ -183,7 +165,7 @@
     
     ResourceType type;
     
-    if (!context_.GetIndex().LookupResourceType(type, sourceStudy) ||
+    if (!GetContext().GetIndex().LookupResourceType(type, sourceStudy) ||
         type != ResourceType_Study)
     {
       throw OrthancException(ErrorCode_UnknownResource,
@@ -219,7 +201,7 @@
     {
       throw OrthancException(ErrorCode_BadSequenceOfCalls);
     }
-    else if (!context_.GetIndex().LookupParent(parent, series, ResourceType_Study) ||
+    else if (!GetContext().GetIndex().LookupParent(parent, series, ResourceType_Study) ||
              parent != sourceStudy_)
     {
       throw OrthancException(ErrorCode_UnknownResource,
@@ -232,7 +214,7 @@
 
       // Add all the instances of the series as to be processed
       std::list<std::string> instances;
-      context_.GetIndex().GetChildren(instances, series);
+      GetContext().GetIndex().GetChildren(instances, series);
 
       for (std::list<std::string>::const_iterator
              it = instances.begin(); it != instances.end(); ++it)
@@ -243,17 +225,6 @@
   }
 
 
-  void SplitStudyJob::SetKeepSource(bool keep)
-  {
-    if (IsStarted())
-    {
-      throw OrthancException(ErrorCode_BadSequenceOfCalls);
-    }
-
-    keepSource_ = keep;
-  }
-
-
   bool SplitStudyJob::LookupTargetSeriesUid(std::string& uid,
                                             const std::string& series) const
   {
@@ -315,7 +286,7 @@
     
   void SplitStudyJob::GetPublicContent(Json::Value& value)
   {
-    SetOfInstancesJob::GetPublicContent(value);
+    CleaningInstancesJob::GetPublicContent(value);
 
     if (!targetStudy_.empty())
     {
@@ -326,7 +297,6 @@
   }
 
 
-  static const char* KEEP_SOURCE = "KeepSource";
   static const char* SOURCE_STUDY = "SourceStudy";
   static const char* TARGET_STUDY = "TargetStudy";
   static const char* TARGET_STUDY_UID = "TargetStudyUID";
@@ -338,8 +308,8 @@
 
   SplitStudyJob::SplitStudyJob(ServerContext& context,
                                const Json::Value& serialized) :
-    SetOfInstancesJob(serialized),  // (*)
-    context_(context)
+    CleaningInstancesJob(context, serialized,
+                         false /* by default, remove source instances */)  // (*)
   {
     if (!HasTrailingStep())
     {
@@ -349,7 +319,6 @@
 
     Setup();
 
-    keepSource_ = SerializationToolbox::ReadBoolean(serialized, KEEP_SOURCE);
     sourceStudy_ = SerializationToolbox::ReadString(serialized, SOURCE_STUDY);
     targetStudy_ = SerializationToolbox::ReadString(serialized, TARGET_STUDY);
     targetStudyUid_ = SerializationToolbox::ReadString(serialized, TARGET_STUDY_UID);
@@ -362,13 +331,12 @@
   
   bool SplitStudyJob::Serialize(Json::Value& target)
   {
-    if (!SetOfInstancesJob::Serialize(target))
+    if (!CleaningInstancesJob::Serialize(target))
     {
       return false;
     }
     else
     {
-      target[KEEP_SOURCE] = keepSource_;
       target[SOURCE_STUDY] = sourceStudy_;
       target[TARGET_STUDY] = targetStudy_;
       target[TARGET_STUDY_UID] = targetStudyUid_;
--- a/OrthancServer/ServerJobs/SplitStudyJob.h	Mon May 18 17:41:05 2020 +0200
+++ b/OrthancServer/ServerJobs/SplitStudyJob.h	Mon May 18 18:20:19 2020 +0200
@@ -33,24 +33,22 @@
 
 #pragma once
 
-#include "../../Core/JobsEngine/SetOfInstancesJob.h"
 #include "../../Core/DicomFormat/DicomTag.h"
 #include "../DicomInstanceOrigin.h"
+#include "CleaningInstancesJob.h"
 
 namespace Orthanc
 {
   class ServerContext;
   
-  class SplitStudyJob : public SetOfInstancesJob
+  class SplitStudyJob : public CleaningInstancesJob
   {
   private:
     typedef std::map<std::string, std::string>  SeriesUidMap;
     typedef std::map<DicomTag, std::string>     Replacements;
     
     
-    ServerContext&         context_;
     std::set<DicomTag>     allowedTags_;
-    bool                   keepSource_;
     std::string            sourceStudy_;
     std::string            targetStudy_;
     std::string            targetStudyUid_;
@@ -66,8 +64,6 @@
   protected:
     virtual bool HandleInstance(const std::string& instance);
 
-    virtual bool HandleTrailingStep();
-    
   public:
     SplitStudyJob(ServerContext& context,
                   const std::string& sourceStudy);
@@ -92,13 +88,6 @@
 
     void AddSourceSeries(const std::string& series);
 
-    bool IsKeepSource() const
-    {
-      return keepSource_;
-    }
-    
-    void SetKeepSource(bool keep);
-
     bool LookupTargetSeriesUid(std::string& uid,
                                const std::string& series) const;