changeset 1134:87fbeb823375 broker

allocating messages from oracle commands on the stack
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 06 Nov 2019 15:16:45 +0100
parents 0e3a3be313fd
children a0a33e5ea5bb
files Framework/Loaders/LoaderStateMachine.cpp Framework/Loaders/OrthancSeriesVolumeProgressiveLoader.cpp Framework/Oracle/GenericOracleRunner.cpp Framework/Oracle/GenericOracleRunner.h Framework/Oracle/GetOrthancImageCommand.cpp Framework/Oracle/GetOrthancImageCommand.h Framework/Oracle/GetOrthancWebViewerJpegCommand.cpp Framework/Oracle/GetOrthancWebViewerJpegCommand.h Framework/Oracle/HttpCommand.cpp Framework/Oracle/HttpCommand.h Framework/Oracle/OracleCommandExceptionMessage.h Framework/Oracle/OrthancRestApiCommand.cpp Framework/Oracle/OrthancRestApiCommand.h Framework/Oracle/ParseDicomFileCommand.cpp Framework/Oracle/ParseDicomFileCommand.h Framework/Oracle/ThreadedOracle.cpp
diffstat 16 files changed, 169 insertions(+), 170 deletions(-) [+]
line wrap: on
line diff
--- a/Framework/Loaders/LoaderStateMachine.cpp	Wed Nov 06 12:56:23 2019 +0100
+++ b/Framework/Loaders/LoaderStateMachine.cpp	Wed Nov 06 15:16:45 2019 +0100
@@ -144,7 +144,7 @@
       activeCommands_--;
       try
       {
-        dynamic_cast<State&>(message.GetOrigin().GetPayload()).Handle(message);
+        dynamic_cast<State&>(message.GetCommand().GetPayload()).Handle(message);
         Step();
       }
       catch (Orthanc::OrthancException& e)
--- a/Framework/Loaders/OrthancSeriesVolumeProgressiveLoader.cpp	Wed Nov 06 12:56:23 2019 +0100
+++ b/Framework/Loaders/OrthancSeriesVolumeProgressiveLoader.cpp	Wed Nov 06 15:16:45 2019 +0100
@@ -237,7 +237,7 @@
   }
 
 
-  static unsigned int GetSliceIndexPayload(const OracleCommandBase& command)
+  static unsigned int GetSliceIndexPayload(const IOracleCommand& command)
   {
     return dynamic_cast< const Orthanc::SingleValueObject<unsigned int>& >(command.GetPayload()).GetValue();
   }
@@ -394,7 +394,7 @@
 
   void OrthancSeriesVolumeProgressiveLoader::LoadBestQualitySliceContent(const GetOrthancImageCommand::SuccessMessage& message)
   {
-    SetSliceContent(GetSliceIndexPayload(message.GetOrigin()), message.GetImage(), BEST_QUALITY);
+    SetSliceContent(GetSliceIndexPayload(message.GetCommand()), message.GetImage(), BEST_QUALITY);
   }
 
 
@@ -402,7 +402,7 @@
   {
     unsigned int quality;
       
-    switch (message.GetOrigin().GetQuality())
+    switch (dynamic_cast<const GetOrthancWebViewerJpegCommand&>(message.GetCommand()).GetQuality())
     {
       case 50:
         quality = LOW_QUALITY;
@@ -416,7 +416,7 @@
         throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
     }
       
-    SetSliceContent(GetSliceIndexPayload(message.GetOrigin()), message.GetImage(), quality);
+    SetSliceContent(GetSliceIndexPayload(message.GetCommand()), message.GetImage(), quality);
   }
 
 
--- a/Framework/Oracle/GenericOracleRunner.cpp	Wed Nov 06 12:56:23 2019 +0100
+++ b/Framework/Oracle/GenericOracleRunner.cpp	Wed Nov 06 15:16:45 2019 +0100
@@ -100,7 +100,9 @@
   }
 
 
-  static IMessage* Execute(const HttpCommand& command)
+  static void RunInternal(boost::weak_ptr<IObserver> receiver,
+                          IMessageEmitter& emitter,
+                          HttpCommand& command)
   {
     Orthanc::HttpClient client;
     client.SetUrl(command.GetUrl());
@@ -126,12 +128,15 @@
 
     DecodeAnswer(answer, answerHeaders);
 
-    return new HttpCommand::SuccessMessage(command, answerHeaders, answer);
+    HttpCommand::SuccessMessage message(command, answerHeaders, answer);
+    emitter.EmitMessage(receiver, message);
   }
 
 
-  static IMessage* Execute(const Orthanc::WebServiceParameters& orthanc,
-                           const OrthancRestApiCommand& command)
+  static void RunInternal(boost::weak_ptr<IObserver> receiver,
+                          IMessageEmitter& emitter,
+                          const Orthanc::WebServiceParameters& orthanc,
+                          OrthancRestApiCommand& command)
   {
     Orthanc::HttpClient client(orthanc, command.GetUri());
     client.SetMethod(command.GetMethod());
@@ -151,12 +156,15 @@
 
     DecodeAnswer(answer, answerHeaders);
 
-    return new OrthancRestApiCommand::SuccessMessage(command, answerHeaders, answer);
+    OrthancRestApiCommand::SuccessMessage message(command, answerHeaders, answer);
+    emitter.EmitMessage(receiver, message);
   }
 
 
-  static IMessage* Execute(const Orthanc::WebServiceParameters& orthanc,
-                           const GetOrthancImageCommand& command)
+  static void RunInternal(boost::weak_ptr<IObserver> receiver,
+                          IMessageEmitter& emitter,
+                          const Orthanc::WebServiceParameters& orthanc,
+                          GetOrthancImageCommand& command)
   {
     Orthanc::HttpClient client(orthanc, command.GetUri());
     client.SetTimeout(command.GetTimeout());
@@ -169,12 +177,14 @@
 
     DecodeAnswer(answer, answerHeaders);
 
-    return command.ProcessHttpAnswer(answer, answerHeaders);
+    command.ProcessHttpAnswer(receiver, emitter, answer, answerHeaders);
   }
 
 
-  static IMessage* Execute(const Orthanc::WebServiceParameters& orthanc,
-                           const GetOrthancWebViewerJpegCommand& command)
+  static void RunInternal(boost::weak_ptr<IObserver> receiver,
+                          IMessageEmitter& emitter,
+                          const Orthanc::WebServiceParameters& orthanc,
+                          GetOrthancWebViewerJpegCommand& command)
   {
     Orthanc::HttpClient client(orthanc, command.GetUri());
     client.SetTimeout(command.GetTimeout());
@@ -187,7 +197,7 @@
 
     DecodeAnswer(answer, answerHeaders);
 
-    return command.ProcessHttpAnswer(answer);
+    command.ProcessHttpAnswer(receiver, emitter, answer);
   }
 
 
@@ -212,21 +222,26 @@
   }
 
 
-  static IMessage* Execute(const std::string& root,
-                           ReadFileCommand& command)
+  static void RunInternal(boost::weak_ptr<IObserver> receiver,
+                          IMessageEmitter& emitter,
+                          const std::string& root,
+                          ReadFileCommand& command)
   {
     std::string path = GetPath(root, command.GetPath());
 
     std::string content;
     Orthanc::SystemToolbox::ReadFile(content, path, true /* log */);
 
-    return new ReadFileCommand::SuccessMessage(command, content);
+    ReadFileCommand::SuccessMessage message(command, content);
+    emitter.EmitMessage(receiver, message);
   }
 
 
 #if ORTHANC_ENABLE_DCMTK == 1
-  static ParseDicomFileCommand::SuccessMessage* Execute(const std::string& root,
-                                                        const ParseDicomFileCommand& command)
+  static void RunInternal(boost::weak_ptr<IObserver> receiver,
+                          IMessageEmitter& emitter,
+                          const std::string& root,
+                          ParseDicomFileCommand& command)
   {
     std::string path = GetPath(root, command.GetPath());
 
@@ -271,8 +286,10 @@
 
     if (ok)
     {
-      return new ParseDicomFileCommand::SuccessMessage
-        (command, dicom, static_cast<size_t>(fileSize), command.IsPixelDataIncluded());
+      Orthanc::ParsedDicomFile parsed(dicom);
+      ParseDicomFileCommand::SuccessMessage message
+        (command, parsed, static_cast<size_t>(fileSize), command.IsPixelDataIncluded());
+      emitter.EmitMessage(receiver, message);
     }
     else
     {
@@ -281,10 +298,12 @@
     }
   }
 
-
-  static ParseDicomFileCommand::SuccessMessage* Execute(boost::shared_ptr<ParsedDicomFileCache> cache,
-                                                        const std::string& root,
-                                                        const ParseDicomFileCommand& command)
+  
+  static void RunInternal(boost::weak_ptr<IObserver> receiver,
+                          IMessageEmitter& emitter,
+                          boost::shared_ptr<ParsedDicomFileCache> cache,
+                          const std::string& root,
+                          ParseDicomFileCommand& command)
   {
 #if 0
     // The code to use the cache is buggy in multithreaded environments => TODO FIX
@@ -299,11 +318,13 @@
           // Reuse the DICOM file from the cache
           return new ParseDicomFileCommand::SuccessMessage(
             command, reader.GetDicom(), reader.GetFileSize(), reader.HasPixelData());
+          emitter.EmitMessage(receiver, message);
+          return;
         }
       }
       
       // Not in the cache, first read and parse the DICOM file
-      std::auto_ptr<ParseDicomFileCommand::SuccessMessage> message(Execute(root, command));
+      std::auto_ptr<ParseDicomFileCommand::SuccessMessage> message(RunInternal(root, command));
 
       // Secondly, store it into the cache for future use
       assert(&message->GetOrigin() == &command);
@@ -315,18 +336,22 @@
     else
     {
       // No cache available
-      return Execute(root, command);
+      return RunInternal(root, command);
     }
 #else
-    return Execute(root, command);
+    return RunInternal(receiver, emitter, root, command);
 #endif
   }
   
 #endif
 
 
-  IMessage* GenericOracleRunner::Run(IOracleCommand& command)
+  void GenericOracleRunner::Run(boost::weak_ptr<IObserver> receiver,
+                                IMessageEmitter& emitter,
+                                IOracleCommand& command)
   {
+    Orthanc::ErrorCode error = Orthanc::ErrorCode_Success;
+    
     try
     {
       switch (command.GetType())
@@ -336,24 +361,34 @@
                                           "Sleep command cannot be executed by the runner");
 
         case IOracleCommand::Type_Http:
-          return Execute(dynamic_cast<const HttpCommand&>(command));
+          RunInternal(receiver, emitter, dynamic_cast<HttpCommand&>(command));
+          break;
 
         case IOracleCommand::Type_OrthancRestApi:
-          return Execute(orthanc_, dynamic_cast<const OrthancRestApiCommand&>(command));
+          RunInternal(receiver, emitter, orthanc_,
+                      dynamic_cast<OrthancRestApiCommand&>(command));
+          break;
 
         case IOracleCommand::Type_GetOrthancImage:
-          return Execute(orthanc_, dynamic_cast<const GetOrthancImageCommand&>(command));
+          RunInternal(receiver, emitter, orthanc_,
+                      dynamic_cast<GetOrthancImageCommand&>(command));
+          break;
 
         case IOracleCommand::Type_GetOrthancWebViewerJpeg:
-          return Execute(orthanc_, dynamic_cast<const GetOrthancWebViewerJpegCommand&>(command));
+          RunInternal(receiver, emitter, orthanc_,
+                      dynamic_cast<GetOrthancWebViewerJpegCommand&>(command));
+          break;
 
         case IOracleCommand::Type_ReadFile:
-          return Execute(rootDirectory_, dynamic_cast<ReadFileCommand&>(command));
+          RunInternal(receiver, emitter, rootDirectory_,
+                      dynamic_cast<ReadFileCommand&>(command));
+          break;
 
         case IOracleCommand::Type_ParseDicomFile:
 #if ORTHANC_ENABLE_DCMTK == 1
-          return Execute(dicomCache_, rootDirectory_,
-                         dynamic_cast<const ParseDicomFileCommand&>(command));
+          RunInternal(receiver, emitter, dicomCache_, rootDirectory_,
+                      dynamic_cast<ParseDicomFileCommand&>(command));
+          break;
 #else
           throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented,
                                           "DCMTK must be enabled to parse DICOM files");
@@ -366,12 +401,15 @@
     catch (Orthanc::OrthancException& e)
     {
       LOG(ERROR) << "Exception within the oracle: " << e.What();
-      return new OracleCommandExceptionMessage(command, e);
+      error = e.GetErrorCode();
     }
     catch (...)
     {
       LOG(ERROR) << "Threaded exception within the oracle";
-      return new OracleCommandExceptionMessage(command, Orthanc::ErrorCode_InternalError);
+      error = Orthanc::ErrorCode_InternalError;
     }
+
+    OracleCommandExceptionMessage message(command, error);
+    emitter.EmitMessage(receiver, message);
   }
 }
--- a/Framework/Oracle/GenericOracleRunner.h	Wed Nov 06 12:56:23 2019 +0100
+++ b/Framework/Oracle/GenericOracleRunner.h	Wed Nov 06 15:16:45 2019 +0100
@@ -30,6 +30,7 @@
 #endif
 
 #include "IOracleCommand.h"
+#include "../Messages/IMessageEmitter.h"
 
 #include <Core/Enumerations.h>  // For ORTHANC_OVERRIDE
 #include <Core/WebServiceParameters.h>
@@ -79,6 +80,8 @@
     }
 #endif
 
-    IMessage* Run(IOracleCommand& command);
+    void Run(boost::weak_ptr<IObserver> receiver,
+             IMessageEmitter& emitter,
+             IOracleCommand& command);
   };
 }
--- a/Framework/Oracle/GetOrthancImageCommand.cpp	Wed Nov 06 12:56:23 2019 +0100
+++ b/Framework/Oracle/GetOrthancImageCommand.cpp	Wed Nov 06 15:16:45 2019 +0100
@@ -29,20 +29,6 @@
 
 namespace OrthancStone
 {
-  GetOrthancImageCommand::SuccessMessage::SuccessMessage(const GetOrthancImageCommand& command,
-                                                         Orthanc::ImageAccessor* image,   // Takes ownership
-                                                         Orthanc::MimeType mime) :
-    OriginMessage(command),
-    image_(image),
-    mime_(mime)
-  {
-    if (image == NULL)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
-    }
-  }
-
-
   GetOrthancImageCommand::GetOrthancImageCommand() :
     uri_("/"),
     timeout_(600),
@@ -82,8 +68,11 @@
     }
   }
 
-  IMessage* GetOrthancImageCommand::ProcessHttpAnswer(const std::string& answer,
-                                                      const HttpHeaders& answerHeaders) const
+  
+  void GetOrthancImageCommand::ProcessHttpAnswer(boost::weak_ptr<IObserver> receiver,
+                                                 IMessageEmitter& emitter,
+                                                 const std::string& answer,
+                                                 const HttpHeaders& answerHeaders)
   {
     Orthanc::MimeType contentType = Orthanc::MimeType_Binary;
 
@@ -145,6 +134,7 @@
       }
     }
 
-    return new SuccessMessage(*this, image.release(), contentType);
+    SuccessMessage message(*this, *image, contentType);
+    emitter.EmitMessage(receiver, message);
   }
 }
--- a/Framework/Oracle/GetOrthancImageCommand.h	Wed Nov 06 12:56:23 2019 +0100
+++ b/Framework/Oracle/GetOrthancImageCommand.h	Wed Nov 06 15:16:45 2019 +0100
@@ -21,7 +21,7 @@
 
 #pragma once
 
-#include "../Messages/IMessage.h"
+#include "../Messages/IMessageEmitter.h"
 #include "OracleCommandBase.h"
 
 #include <Core/Images/ImageAccessor.h>
@@ -35,22 +35,27 @@
   public:
     typedef std::map<std::string, std::string>  HttpHeaders;
 
-    class SuccessMessage : public OriginMessage<GetOrthancImageCommand>
+    class SuccessMessage : public OracleMessageBase
     {
       ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
       
     private:
-      std::auto_ptr<Orthanc::ImageAccessor>  image_;
-      Orthanc::MimeType                      mime_;
+      const Orthanc::ImageAccessor&  image_;
+      Orthanc::MimeType              mime_;
 
     public:
-      SuccessMessage(const GetOrthancImageCommand& command,
-                     Orthanc::ImageAccessor* image,   // Takes ownership
-                     Orthanc::MimeType mime);
+      SuccessMessage(GetOrthancImageCommand& command,
+                     const Orthanc::ImageAccessor& image,
+                     Orthanc::MimeType mime) :
+        OracleMessageBase(command),
+        image_(image),
+        mime_(mime)
+      {
+      }
 
       const Orthanc::ImageAccessor& GetImage() const
       {
-        return *image_;
+        return image_;
       }
 
       Orthanc::MimeType GetMimeType() const
@@ -111,7 +116,9 @@
       return timeout_;
     }
 
-    IMessage* ProcessHttpAnswer(const std::string& answer,
-                                const HttpHeaders& answerHeaders) const;
+    void ProcessHttpAnswer(boost::weak_ptr<IObserver> receiver,
+                           IMessageEmitter& emitter,
+                           const std::string& answer,
+                           const HttpHeaders& answerHeaders);
   };
 }
--- a/Framework/Oracle/GetOrthancWebViewerJpegCommand.cpp	Wed Nov 06 12:56:23 2019 +0100
+++ b/Framework/Oracle/GetOrthancWebViewerJpegCommand.cpp	Wed Nov 06 15:16:45 2019 +0100
@@ -34,18 +34,6 @@
 
 namespace OrthancStone
 {
-  GetOrthancWebViewerJpegCommand::SuccessMessage::SuccessMessage(const GetOrthancWebViewerJpegCommand& command,
-                                                                 Orthanc::ImageAccessor* image) :   // Takes ownership
-    OriginMessage(command),
-    image_(image)
-  {
-    if (image == NULL)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
-    }
-  }
-
-
   GetOrthancWebViewerJpegCommand::GetOrthancWebViewerJpegCommand() :
     frame_(0),
     quality_(95),
@@ -76,7 +64,9 @@
   }
 
 
-  IMessage* GetOrthancWebViewerJpegCommand::ProcessHttpAnswer(const std::string& answer) const
+  void GetOrthancWebViewerJpegCommand::ProcessHttpAnswer(boost::weak_ptr<IObserver> receiver,
+                                                         IMessageEmitter& emitter,
+                                                         const std::string& answer)
   {
     // This code comes from older "OrthancSlicesLoader::ParseSliceImageJpeg()"
       
@@ -147,7 +137,9 @@
       }
       else
       {
-        return new SuccessMessage(*this, reader.release());
+        SuccessMessage message(*this, *reader);
+        emitter.EmitMessage(receiver, message);
+        return;
       }
     }
     
@@ -164,7 +156,9 @@
       }
       else
       {
-        return new SuccessMessage(*this, reader.release());
+        SuccessMessage message(*this, *reader);
+        emitter.EmitMessage(receiver, message);
+        return;
       }
     }
     
@@ -205,6 +199,7 @@
       Orthanc::ImageProcessing::ShiftScale(*image, offset, scaling, true);
     }
 
-    return new SuccessMessage(*this, image.release());
+    SuccessMessage message(*this, *image);
+    emitter.EmitMessage(receiver, message);
   }
 }
--- a/Framework/Oracle/GetOrthancWebViewerJpegCommand.h	Wed Nov 06 12:56:23 2019 +0100
+++ b/Framework/Oracle/GetOrthancWebViewerJpegCommand.h	Wed Nov 06 15:16:45 2019 +0100
@@ -21,7 +21,7 @@
 
 #pragma once
 
-#include "../Messages/IMessage.h"
+#include "../Messages/IMessageEmitter.h"
 #include "OracleCommandBase.h"
 
 #include <Core/Images/ImageAccessor.h>
@@ -35,20 +35,24 @@
   public:
     typedef std::map<std::string, std::string>  HttpHeaders;
 
-    class SuccessMessage : public OriginMessage<GetOrthancWebViewerJpegCommand>
+    class SuccessMessage : public OracleMessageBase
     {
       ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
       
     private:
-      std::auto_ptr<Orthanc::ImageAccessor>  image_;
+      const Orthanc::ImageAccessor&  image_;
 
     public:
-      SuccessMessage(const GetOrthancWebViewerJpegCommand& command,
-                     Orthanc::ImageAccessor* image);   // Takes ownership
+      SuccessMessage(GetOrthancWebViewerJpegCommand& command,
+                     const Orthanc::ImageAccessor& image) :
+        OracleMessageBase(command),
+        image_(image)
+      {
+      }
 
       const Orthanc::ImageAccessor& GetImage() const
       {
-        return *image_;
+        return image_;
       }
     };
 
@@ -128,6 +132,8 @@
 
     std::string GetUri() const;
 
-    IMessage* ProcessHttpAnswer(const std::string& answer) const;
+    void ProcessHttpAnswer(boost::weak_ptr<IObserver> receiver,
+                           IMessageEmitter& emitter,
+                           const std::string& answer);
   };
 }
--- a/Framework/Oracle/HttpCommand.cpp	Wed Nov 06 12:56:23 2019 +0100
+++ b/Framework/Oracle/HttpCommand.cpp	Wed Nov 06 15:16:45 2019 +0100
@@ -28,10 +28,10 @@
 
 namespace OrthancStone
 {
-  HttpCommand::SuccessMessage::SuccessMessage(const HttpCommand& command,
+  HttpCommand::SuccessMessage::SuccessMessage(HttpCommand& command,
                                               const HttpHeaders& answerHeaders,
-                                              std::string& answer) :
-    OriginMessage(command),
+                                              const std::string& answer) :
+    OracleMessageBase(command),
     headers_(answerHeaders),
     answer_(answer)
   {
--- a/Framework/Oracle/HttpCommand.h	Wed Nov 06 12:56:23 2019 +0100
+++ b/Framework/Oracle/HttpCommand.h	Wed Nov 06 15:16:45 2019 +0100
@@ -36,18 +36,18 @@
   public:
     typedef std::map<std::string, std::string>  HttpHeaders;
 
-    class SuccessMessage : public OriginMessage<HttpCommand>
+    class SuccessMessage : public OracleMessageBase
     {
       ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
       
     private:
-      HttpHeaders   headers_;
-      std::string   answer_;
+      const HttpHeaders&  headers_;
+      const std::string&  answer_;
 
     public:
-      SuccessMessage(const HttpCommand& command,
+      SuccessMessage(HttpCommand& command,
                      const HttpHeaders& answerHeaders,
-                     std::string& answer  /* will be swapped to avoid a memcpy() */);
+                     const std::string& answer);
 
       const std::string& GetAnswer() const
       {
@@ -56,7 +56,7 @@
 
       void ParseJsonBody(Json::Value& target) const;
 
-      const HttpHeaders&  GetAnswerHeaders() const
+      const HttpHeaders& GetAnswerHeaders() const
       {
         return headers_;
       }
--- a/Framework/Oracle/OracleCommandExceptionMessage.h	Wed Nov 06 12:56:23 2019 +0100
+++ b/Framework/Oracle/OracleCommandExceptionMessage.h	Wed Nov 06 15:16:45 2019 +0100
@@ -37,13 +37,6 @@
 
   public:
     OracleCommandExceptionMessage(IOracleCommand& command,
-                                  const Orthanc::OrthancException& exception) :
-      OracleMessageBase(command),
-      exception_(exception)
-    {
-    }
-
-    OracleCommandExceptionMessage(IOracleCommand& command,
                                   const Orthanc::ErrorCode& error) :
       OracleMessageBase(command),
       exception_(error)
--- a/Framework/Oracle/OrthancRestApiCommand.cpp	Wed Nov 06 12:56:23 2019 +0100
+++ b/Framework/Oracle/OrthancRestApiCommand.cpp	Wed Nov 06 15:16:45 2019 +0100
@@ -28,16 +28,6 @@
 
 namespace OrthancStone
 {
-  OrthancRestApiCommand::SuccessMessage::SuccessMessage(const OrthancRestApiCommand& command,
-                                                        const HttpHeaders& answerHeaders,
-                                                        std::string& answer) :
-    OriginMessage(command),
-    headers_(answerHeaders),
-    answer_(answer)
-  {
-  }
-
-
   void OrthancRestApiCommand::SuccessMessage::ParseJsonBody(Json::Value& target) const
   {
     Json::Reader reader;
--- a/Framework/Oracle/OrthancRestApiCommand.h	Wed Nov 06 12:56:23 2019 +0100
+++ b/Framework/Oracle/OrthancRestApiCommand.h	Wed Nov 06 15:16:45 2019 +0100
@@ -36,19 +36,24 @@
   public:
     typedef std::map<std::string, std::string>  HttpHeaders;
 
-    class SuccessMessage : public OriginMessage<OrthancRestApiCommand>
+    class SuccessMessage : public OracleMessageBase
     {
       ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
       
     private:
-      HttpHeaders   headers_;
-      std::string   answer_;
+      const HttpHeaders&  headers_;
+      const std::string&  answer_;
 
     public:
-      SuccessMessage(const OrthancRestApiCommand& command,
+      SuccessMessage(OrthancRestApiCommand& command,
                      const HttpHeaders& answerHeaders,
-                     std::string& answer  /* will be swapped to avoid a memcpy() */);
-
+                     const std::string& answer) :
+        OracleMessageBase(command),
+        headers_(answerHeaders),
+        answer_(answer)
+      {
+      }
+      
       const std::string& GetAnswer() const
       {
         return answer_;
--- a/Framework/Oracle/ParseDicomFileCommand.cpp	Wed Nov 06 12:56:23 2019 +0100
+++ b/Framework/Oracle/ParseDicomFileCommand.cpp	Wed Nov 06 15:16:45 2019 +0100
@@ -27,9 +27,16 @@
 
 namespace OrthancStone
 {
-  void ParseDicomFileCommand::SuccessMessage::Setup()
+  ParseDicomFileCommand::SuccessMessage::SuccessMessage(ParseDicomFileCommand& command,
+                                                        Orthanc::ParsedDicomFile& dicom,
+                                                        size_t fileSize,
+                                                        bool hasPixelData) :
+    OracleMessageBase(command),
+    dicom_(dicom),
+    fileSize_(fileSize),
+    hasPixelData_(hasPixelData)
   {
-    if (!dicom_->GetTagValue(sopInstanceUid_, Orthanc::DICOM_TAG_SOP_INSTANCE_UID))
+    if (!dicom.GetTagValue(sopInstanceUid_, Orthanc::DICOM_TAG_SOP_INSTANCE_UID))
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat,
                                       "DICOM instance missing tag SOPInstanceUID");
@@ -37,32 +44,6 @@
   }
 
 
-  ParseDicomFileCommand::SuccessMessage::SuccessMessage(const ParseDicomFileCommand& command,
-                                                        DcmFileFormat& dicom,
-                                                        size_t fileSize,
-                                                        bool hasPixelData) :
-    OriginMessage(command),
-    fileSize_(fileSize),
-    hasPixelData_(hasPixelData)
-  {
-    dicom_.reset(new Orthanc::ParsedDicomFile(dicom));
-    Setup();
-  }
-
-
-  ParseDicomFileCommand::SuccessMessage::SuccessMessage(const ParseDicomFileCommand& command,
-                                                        boost::shared_ptr<Orthanc::ParsedDicomFile> dicom,
-                                                        size_t fileSize,
-                                                        bool hasPixelData) :
-    OriginMessage(command),
-    dicom_(dicom),
-    fileSize_(fileSize),
-    hasPixelData_(hasPixelData)
-  {
-    Setup();
-  }
-
-
   std::string ParseDicomFileCommand::GetDicomDirPath(const std::string& dicomDirPath,
                                                      const std::string& file)
   {
--- a/Framework/Oracle/ParseDicomFileCommand.h	Wed Nov 06 12:56:23 2019 +0100
+++ b/Framework/Oracle/ParseDicomFileCommand.h	Wed Nov 06 15:16:45 2019 +0100
@@ -41,30 +41,23 @@
   class ParseDicomFileCommand : public OracleCommandBase
   {
   public:
-    class SuccessMessage : public OriginMessage<ParseDicomFileCommand>
+    class SuccessMessage : public OracleMessageBase
     {
       ORTHANC_STONE_MESSAGE(__FILE__, __LINE__);
 
     private:
-      boost::shared_ptr<Orthanc::ParsedDicomFile>  dicom_;
-      size_t                                       fileSize_;
-      bool                                         hasPixelData_;
-      std::string                                  sopInstanceUid_;
+      Orthanc::ParsedDicomFile&  dicom_;
+      size_t                     fileSize_;
+      bool                       hasPixelData_;
+      std::string                sopInstanceUid_;
 
-      void Setup();
-      
     public:
-      SuccessMessage(const ParseDicomFileCommand& command,
-                     DcmFileFormat& dicom,
+      SuccessMessage(ParseDicomFileCommand& command,
+                     Orthanc::ParsedDicomFile& dicom,
                      size_t fileSize,
                      bool hasPixelData);
       
-      SuccessMessage(const ParseDicomFileCommand& command,
-                     boost::shared_ptr<Orthanc::ParsedDicomFile> dicom,
-                     size_t fileSize,
-                     bool hasPixelData);
-      
-      boost::shared_ptr<Orthanc::ParsedDicomFile> GetDicom() const
+      Orthanc::ParsedDicomFile& GetDicom() const
       {
         return dicom_;
       }
--- a/Framework/Oracle/ThreadedOracle.cpp	Wed Nov 06 12:56:23 2019 +0100
+++ b/Framework/Oracle/ThreadedOracle.cpp	Wed Nov 06 15:16:45 2019 +0100
@@ -189,10 +189,8 @@
           }
 #endif
         }
-        
-        std::auto_ptr<IMessage> message(runner.Run(item.GetCommand()));
-        
-        emitter_.EmitMessage(item.GetReceiver(), *message);
+
+        runner.Run(item.GetReceiver(), emitter_, item.GetCommand());
       }
     }
   }