changeset 2808:37583cd183ed

primitives to create jobs from plugins
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 05 Sep 2018 17:57:06 +0200
parents 6356e2ceb493
children b509d9a4958b
files CMakeLists.txt OrthancServer/ServerContext.cpp Plugins/Engine/OrthancPlugins.cpp Plugins/Engine/OrthancPlugins.h Plugins/Engine/PluginsEnumerations.cpp Plugins/Engine/PluginsEnumerations.h Plugins/Include/orthanc/OrthancCPlugin.h
diffstat 7 files changed, 221 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Tue Sep 04 15:58:26 2018 +0200
+++ b/CMakeLists.txt	Wed Sep 05 17:57:06 2018 +0200
@@ -125,6 +125,7 @@
     Plugins/Engine/OrthancPlugins.cpp
     Plugins/Engine/PluginsEnumerations.cpp
     Plugins/Engine/PluginsErrorDictionary.cpp
+    Plugins/Engine/PluginsJob.cpp
     Plugins/Engine/PluginsManager.cpp
     )
 
--- a/OrthancServer/ServerContext.cpp	Tue Sep 04 15:58:26 2018 +0200
+++ b/OrthancServer/ServerContext.cpp	Wed Sep 05 17:57:06 2018 +0200
@@ -165,11 +165,24 @@
       if (index_.LookupGlobalProperty(serialized, GlobalProperty_JobsRegistry))
       {
         LOG(WARNING) << "Reloading the jobs from the last execution of Orthanc";
-        OrthancJobUnserializer unserializer(*this);
 
         try
         {
-          jobsEngine_.LoadRegistryFromString(unserializer, serialized);
+          bool plugin = false;
+        
+#if ORTHANC_ENABLE_PLUGINS == 1
+          if (HasPlugins() &&
+              plugins_->UnserializeJob(serialized))
+          {
+            plugin = true;
+          }
+#endif
+
+          if (!plugin)
+          {
+            OrthancJobUnserializer unserializer(*this);
+            jobsEngine_.LoadRegistryFromString(unserializer, serialized);
+          }
         }
         catch (OrthancException& e)
         {
--- a/Plugins/Engine/OrthancPlugins.cpp	Tue Sep 04 15:58:26 2018 +0200
+++ b/Plugins/Engine/OrthancPlugins.cpp	Wed Sep 05 17:57:06 2018 +0200
@@ -44,6 +44,7 @@
 #include "../../Core/HttpServer/HttpToolbox.h"
 #include "../../Core/Logging.h"
 #include "../../Core/OrthancException.h"
+#include "../../Core/SerializationToolbox.h"
 #include "../../Core/Toolbox.h"
 #include "../../Core/DicomParsing/FromDcmtkBridge.h"
 #include "../../Core/DicomParsing/ToDcmtkBridge.h"
@@ -62,6 +63,7 @@
 #include "../../Core/Images/ImageProcessing.h"
 #include "../../OrthancServer/DefaultDicomImageDecoder.h"
 #include "PluginsEnumerations.h"
+#include "PluginsJob.h"
 
 #include <boost/regex.hpp> 
 #include <dcmtk/dcmdata/dcdict.h>
@@ -402,6 +404,7 @@
     typedef std::list<OrthancPluginIncomingHttpRequestFilter>  IncomingHttpRequestFilters;
     typedef std::list<OrthancPluginIncomingHttpRequestFilter2>  IncomingHttpRequestFilters2;
     typedef std::list<OrthancPluginDecodeImageCallback>  DecodeImageCallbacks;
+    typedef std::list<OrthancPluginJobsUnserializer>  JobsUnserializers;
     typedef std::map<Property, std::string>  Properties;
 
     PluginsManager manager_;
@@ -412,6 +415,7 @@
     OrthancPluginFindCallback  findCallback_;
     OrthancPluginWorklistCallback  worklistCallback_;
     DecodeImageCallbacks  decodeImageCallbacks_;
+    JobsUnserializers  jobsUnserializers_;
     _OrthancPluginMoveCallback moveCallbacks_;
     IncomingHttpRequestFilters  incomingHttpRequestFilters_;
     IncomingHttpRequestFilters2 incomingHttpRequestFilters2_;
@@ -423,6 +427,7 @@
     boost::mutex findCallbackMutex_;
     boost::mutex worklistCallbackMutex_;
     boost::mutex decodeImageCallbackMutex_;
+    boost::mutex jobsUnserializersMutex_;
     boost::recursive_mutex invokeServiceMutex_;
 
     Properties properties_;
@@ -809,6 +814,7 @@
         sizeof(int32_t) != sizeof(_OrthancPluginDatabaseAnswerType) ||
         sizeof(int32_t) != sizeof(OrthancPluginIdentifierConstraint) ||
         sizeof(int32_t) != sizeof(OrthancPluginInstanceOrigin) ||
+        sizeof(int32_t) != sizeof(OrthancPluginJobStepStatus) ||
         static_cast<int>(OrthancPluginDicomToJsonFlags_IncludeBinary) != static_cast<int>(DicomToJsonFlags_IncludeBinary) ||
         static_cast<int>(OrthancPluginDicomToJsonFlags_IncludePrivateTags) != static_cast<int>(DicomToJsonFlags_IncludePrivateTags) ||
         static_cast<int>(OrthancPluginDicomToJsonFlags_IncludeUnknownTags) != static_cast<int>(DicomToJsonFlags_IncludeUnknownTags) ||
@@ -1168,6 +1174,19 @@
   }
 
 
+  void OrthancPlugins::RegisterJobsUnserializer(const void* parameters)
+  {
+    const _OrthancPluginJobsUnserializer& p = 
+      *reinterpret_cast<const _OrthancPluginJobsUnserializer*>(parameters);
+
+    boost::mutex::scoped_lock lock(pimpl_->jobsUnserializersMutex_);
+
+    pimpl_->jobsUnserializers_.push_back(p.unserializer);
+    LOG(INFO) << "Plugin has registered a callback to unserialize jobs (" 
+              << pimpl_->jobsUnserializers_.size() << " unserializer(s) now active)";
+  }
+
+
   void OrthancPlugins::RegisterIncomingHttpRequestFilter(const void* parameters)
   {
     const _OrthancPluginIncomingHttpRequestFilter& p = 
@@ -2857,6 +2876,19 @@
         CallPeerApi(parameters);
         return true;
 
+      case _OrthancPluginService_SubmitJob:
+      {
+        const _OrthancPluginSubmitJob& p =
+          *reinterpret_cast<const _OrthancPluginSubmitJob*>(parameters);
+
+        std::string uuid;
+
+        PImpl::ServerContextLock lock(*pimpl_);
+        lock.GetContext().GetJobsEngine().GetRegistry().Submit(uuid, new PluginsJob(p), p.priority_);
+        
+        return true;
+      }
+
       default:
         return false;
     }
@@ -2906,6 +2938,10 @@
         RegisterDecodeImageCallback(parameters);
         return true;
 
+      case _OrthancPluginService_RegisterJobsUnserializer:
+        RegisterJobsUnserializer(parameters);
+        return true;
+
       case _OrthancPluginService_RegisterIncomingHttpRequestFilter:
         RegisterIncomingHttpRequestFilter(parameters);
         return true;
@@ -3319,7 +3355,7 @@
     }
   }
 
-
+  
   bool OrthancPlugins::IsAllowed(HttpMethod method,
                                  const char* uri,
                                  const char* ip,
@@ -3394,4 +3430,25 @@
 
     return true;
   }
+
+
+  bool OrthancPlugins::UnserializeJob(const Json::Value& value)
+  {
+    const std::string type = SerializationToolbox::ReadString(value, "Type");
+    const std::string serialized = value.toStyledString();
+
+    boost::mutex::scoped_lock lock(pimpl_->jobsUnserializersMutex_);
+
+    for (PImpl::JobsUnserializers::iterator 
+           unserializer = pimpl_->jobsUnserializers_.begin();
+         unserializer != pimpl_->jobsUnserializers_.end(); ++unserializer)
+    {
+      if ((*unserializer) (type.c_str(), serialized.c_str()) == OrthancPluginErrorCode_Success)
+      {
+        return true;
+      }
+    }
+
+    return false;
+  }
 }
--- a/Plugins/Engine/OrthancPlugins.h	Tue Sep 04 15:58:26 2018 +0200
+++ b/Plugins/Engine/OrthancPlugins.h	Wed Sep 05 17:57:06 2018 +0200
@@ -104,6 +104,8 @@
 
     void RegisterDecodeImageCallback(const void* parameters);
 
+    void RegisterJobsUnserializer(const void* parameters);
+
     void RegisterIncomingHttpRequestFilter(const void* parameters);
 
     void RegisterIncomingHttpRequestFilter2(const void* parameters);
@@ -305,6 +307,8 @@
     bool HasMoveHandler();
 
     virtual IMoveRequestHandler* ConstructMoveRequestHandler();
+
+    bool UnserializeJob(const Json::Value& value);
   };
 }
 
--- a/Plugins/Engine/PluginsEnumerations.cpp	Tue Sep 04 15:58:26 2018 +0200
+++ b/Plugins/Engine/PluginsEnumerations.cpp	Wed Sep 05 17:57:06 2018 +0200
@@ -553,5 +553,42 @@
           throw OrthancException(ErrorCode_ParameterOutOfRange);
       }
     }
+
+
+    OrthancPluginJobStepStatus Convert(JobStepCode step)
+    {
+      switch (step)
+      {
+        case JobStepCode_Success:
+          return OrthancPluginJobStepStatus_Success;
+          
+        case JobStepCode_Failure:
+          return OrthancPluginJobStepStatus_Failure;
+          
+        case JobStepCode_Continue:
+          return OrthancPluginJobStepStatus_Continue;
+        
+        default:
+          throw OrthancException(ErrorCode_ParameterOutOfRange);
+      }
+    }
+
+    JobStepCode Convert(OrthancPluginJobStepStatus step)
+    {
+      switch (step)
+      {
+        case OrthancPluginJobStepStatus_Success:
+          return JobStepCode_Success;
+        
+        case OrthancPluginJobStepStatus_Failure:
+          return JobStepCode_Failure;
+        
+        case OrthancPluginJobStepStatus_Continue:
+          return JobStepCode_Continue;
+        
+        default:
+          throw OrthancException(ErrorCode_ParameterOutOfRange);
+      }
+    }
   }
 }
--- a/Plugins/Engine/PluginsEnumerations.h	Tue Sep 04 15:58:26 2018 +0200
+++ b/Plugins/Engine/PluginsEnumerations.h	Wed Sep 05 17:57:06 2018 +0200
@@ -69,6 +69,10 @@
     ValueRepresentation Convert(OrthancPluginValueRepresentation vr);
 
     OrthancPluginValueRepresentation Convert(ValueRepresentation vr);
+
+    OrthancPluginJobStepStatus Convert(JobStepCode step);
+
+    JobStepCode Convert(OrthancPluginJobStepStatus step);
   }
 }
 
--- a/Plugins/Include/orthanc/OrthancCPlugin.h	Tue Sep 04 15:58:26 2018 +0200
+++ b/Plugins/Include/orthanc/OrthancCPlugin.h	Wed Sep 05 17:57:06 2018 +0200
@@ -23,6 +23,7 @@
  *    - Possibly register a handler for C-Move SCP using OrthancPluginRegisterMoveCallback().
  *    - Possibly register a custom decoder for DICOM images using OrthancPluginRegisterDecodeImageCallback().
  *    - Possibly register a callback to filter incoming HTTP requests using OrthancPluginRegisterIncomingHttpRequestFilter2().
+ *    - Possibly register a callback to unserialize jobs using OrthancPluginRegisterJobsUnserializer().
  * -# <tt>void OrthancPluginFinalize()</tt>:
  *    This function is invoked by Orthanc during its shutdown. The plugin
  *    must free all its memory.
@@ -422,6 +423,7 @@
     _OrthancPluginService_CallHttpClient2 = 27,
     _OrthancPluginService_GenerateUuid = 28,
     _OrthancPluginService_RegisterPrivateDictionaryTag = 29,
+    _OrthancPluginService_SubmitJob = 30,
 
     /* Registration of callbacks */
     _OrthancPluginService_RegisterRestCallback = 1000,
@@ -435,6 +437,7 @@
     _OrthancPluginService_RegisterFindCallback = 1008,
     _OrthancPluginService_RegisterMoveCallback = 1009,
     _OrthancPluginService_RegisterIncomingHttpRequestFilter2 = 1010,
+    _OrthancPluginService_RegisterJobsUnserializer = 1011,
 
     /* Sending answers to REST calls */
     _OrthancPluginService_AnswerBuffer = 2000,
@@ -839,6 +842,17 @@
 
 
   /**
+   * The possible status for one single step of a job.
+   **/
+  typedef enum
+  {
+    OrthancPluginJobStepStatus_Success,   /*!< The job has successfully executed all its steps */
+    OrthancPluginJobStepStatus_Failure,   /*!< The job has failed while executing this step */
+    OrthancPluginJobStepStatus_Continue   /*!< The job has still data to process after this step */
+  } OrthancPluginJobStepStatus;
+
+
+  /**
    * @brief A memory buffer allocated by the core system of Orthanc.
    *
    * A memory buffer allocated by the core system of Orthanc. When the
@@ -1243,6 +1257,16 @@
 
 
 
+  typedef void (*OrthancPluginJobFree) (void* job);
+  typedef float (*OrthancPluginJobGetProgress) (void* job);
+  typedef OrthancPluginJobStepStatus (*OrthancPluginJobStep) (void* job);
+  typedef OrthancPluginErrorCode (*OrthancPluginJobReleaseResources) (void* job);
+  typedef OrthancPluginErrorCode (*OrthancPluginJobReset) (void* job);
+  typedef OrthancPluginErrorCode (*OrthancPluginJobsUnserializer) (const char* jobType,
+                                                                   const char* serialized);
+  
+
+
   /**
    * @brief Data structure that contains information about the Orthanc core.
    **/
@@ -1333,7 +1357,8 @@
         sizeof(int32_t) != sizeof(OrthancPluginDicomToJsonFlags) ||
         sizeof(int32_t) != sizeof(OrthancPluginCreateDicomFlags) ||
         sizeof(int32_t) != sizeof(OrthancPluginIdentifierConstraint) ||
-        sizeof(int32_t) != sizeof(OrthancPluginInstanceOrigin))
+        sizeof(int32_t) != sizeof(OrthancPluginInstanceOrigin) ||
+        sizeof(int32_t) != sizeof(OrthancPluginJobStepStatus))
     {
       /* Mismatch in the size of the enumerations */
       return 0;
@@ -5995,8 +6020,84 @@
 
     return context->InvokeService(context, _OrthancPluginService_CallPeerApi, &params);
   }
+
+
+
+  typedef struct
+  {
+    char**                            resultId_;
+    void                             *job_;
+    int                               priority_;
+    const char                       *type_;
+    const char                       *content_;
+    const char                       *serialized_;
+    OrthancPluginJobFree              free_;
+    OrthancPluginJobGetProgress       getProgress_;
+    OrthancPluginJobStep              step_;
+    OrthancPluginJobReleaseResources  releaseResources_;
+    OrthancPluginJobReset             reset_;
+  } _OrthancPluginSubmitJob;
+
+  ORTHANC_PLUGIN_INLINE char *OrthancPluginSubmitJob(
+    OrthancPluginContext             *context,
+    void                             *job,
+    int                               priority,
+    const char                       *type,
+    const char                       *content,
+    const char                       *serialized,
+    OrthancPluginJobFree              freeJob,
+    OrthancPluginJobGetProgress       getProgress,
+    OrthancPluginJobStep              step,
+    OrthancPluginJobReleaseResources  releaseResources,
+    OrthancPluginJobReset             reset)
+  {
+    char* resultId = NULL;
+
+    _OrthancPluginSubmitJob params;
+    memset(&params, 0, sizeof(params));
+
+    params.resultId_ = &resultId;
+    params.job_ = job;
+    params.priority_ = priority;
+    params.free_ = freeJob;
+    params.type_ = type;
+    params.content_ = content;
+    params.serialized_ = serialized;
+    params.getProgress_ = getProgress;
+    params.step_ = step;
+    params.releaseResources_ = releaseResources;
+    params.reset_ = reset;
+
+    if (context->InvokeService(context, _OrthancPluginService_SubmitJob, &params) != OrthancPluginErrorCode_Success ||
+        resultId == NULL)
+    {
+      /* Error */
+      return NULL;
+    }
+    else
+    {
+      return resultId;
+    }
+  }
   
 
+
+  typedef struct
+  {
+    OrthancPluginJobsUnserializer unserializer;
+  } _OrthancPluginJobsUnserializer;
+
+  ORTHANC_PLUGIN_INLINE void OrthancPluginRegisterJobsUnserializer(
+    OrthancPluginContext*          context,
+    OrthancPluginJobsUnserializer  unserializer)
+  {
+    _OrthancPluginJobsUnserializer params;
+    params.unserializer = unserializer;
+
+    context->InvokeService(context, _OrthancPluginService_RegisterJobsUnserializer, &params);
+  }
+
+
 #ifdef  __cplusplus
 }
 #endif