changeset 377:8eb4fe74000f

refactoring
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 05 Nov 2018 16:18:27 +0100
parents 70256a53ff21
children 814fa32e2fcc
files Applications/Generic/NativeStoneApplicationContext.cpp Applications/Generic/NativeStoneApplicationRunner.cpp Applications/Samples/SimpleViewer/SimpleViewerApplication.cpp Applications/Samples/SimpleViewerApplicationSingleFile.h Applications/Samples/SingleFrameApplication.h Applications/Samples/SingleFrameEditorApplication.h Framework/Layers/OrthancFrameLayerSource.cpp Framework/Messages/IMessage.h Framework/SmartLoader.cpp Framework/Toolbox/IWebService.cpp Framework/Toolbox/IWebService.h Framework/Toolbox/OrthancApiClient.cpp Framework/Toolbox/OrthancApiClient.h Framework/Toolbox/OrthancSlicesLoader.cpp Framework/Volumes/StructureSetLoader.cpp Framework/Widgets/LayerWidget.cpp Platforms/Generic/OracleWebService.h Platforms/Generic/WebServiceCommandBase.cpp Resources/CMake/OrthancStoneConfiguration.cmake
diffstat 19 files changed, 503 insertions(+), 244 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/Generic/NativeStoneApplicationContext.cpp	Mon Nov 05 13:25:03 2018 +0100
+++ b/Applications/Generic/NativeStoneApplicationContext.cpp	Mon Nov 05 16:18:27 2018 +0100
@@ -56,8 +56,6 @@
 
   void NativeStoneApplicationContext::Start()
   {
-    dynamic_cast<OracleWebService*>(webService_)->Start();
-
     if (centralViewport_->HasUpdateContent())
     {
       stopped_ = false;
@@ -74,7 +72,5 @@
     {
       updateThread_.join();
     }
-    
-    dynamic_cast<OracleWebService*>(webService_)->Stop();
   }
 }
--- a/Applications/Generic/NativeStoneApplicationRunner.cpp	Mon Nov 05 13:25:03 2018 +0100
+++ b/Applications/Generic/NativeStoneApplicationRunner.cpp	Mon Nov 05 16:18:27 2018 +0100
@@ -184,34 +184,43 @@
       LogStatusBar statusBar;
 
       NativeStoneApplicationContext context;
-      Oracle oracle(4); // use 4 threads to download content
-      OracleWebService webService(broker_, oracle, webServiceParameters, context);
-      context.SetWebService(webService);
-
-      application_.Initialize(&context, statusBar, parameters);
 
       {
-        NativeStoneApplicationContext::GlobalMutexLocker locker(context);
-        context.SetCentralWidget(application_.GetCentralWidget());
-        context.GetCentralViewport().SetStatusBar(statusBar);
-      }
+        Oracle oracle(4); // use 4 threads to download content
+        oracle.Start();
+
+        {
+          OracleWebService webService(broker_, oracle, webServiceParameters, context);
+          context.SetWebService(webService);
+
+          application_.Initialize(&context, statusBar, parameters);
+
+          {
+            NativeStoneApplicationContext::GlobalMutexLocker locker(context);
+            context.SetCentralWidget(application_.GetCentralWidget());
+            context.GetCentralViewport().SetStatusBar(statusBar);
+          }
 
-      std::string title = application_.GetTitle();
-      if (title.empty())
-      {
-        title = "Stone of Orthanc";
+          std::string title = application_.GetTitle();
+          if (title.empty())
+          {
+            title = "Stone of Orthanc";
+          }
+
+          /****************************************************************
+           * Run the application
+           ****************************************************************/
+
+          Run(context, title, argc, argv);
+
+          /****************************************************************
+           * Finalize the application
+           ****************************************************************/
+
+          oracle.Stop();
+        }
       }
 
-      /****************************************************************
-       * Run the application
-       ****************************************************************/
-
-      Run(context, title, argc, argv);
-
-      /****************************************************************
-       * Finalize the application
-       ****************************************************************/
-
       LOG(WARNING) << "The application is stopping";
       application_.Finalize();
     }
--- a/Applications/Samples/SimpleViewer/SimpleViewerApplication.cpp	Mon Nov 05 13:25:03 2018 +0100
+++ b/Applications/Samples/SimpleViewer/SimpleViewerApplication.cpp	Mon Nov 05 16:18:27 2018 +0100
@@ -21,15 +21,16 @@
 
 #include "SimpleViewerApplication.h"
 
-#if ORTHANC_ENABLE_QT==1
-#include "Qt/SimpleViewerMainWindow.h"
+#if ORTHANC_ENABLE_QT == 1
+#  include "Qt/SimpleViewerMainWindow.h"
 #endif
 
-#if ORTHANC_ENABLE_WASM==1
-#include <Platforms/Wasm/WasmViewport.h>
+#if ORTHANC_ENABLE_WASM == 1
+#  include <Platforms/Wasm/WasmViewport.h>
 #endif
 
-namespace SimpleViewer {
+namespace SimpleViewer
+{
 
   void SimpleViewerApplication::Initialize(StoneApplicationContext* context,
                                            IStatusBar& statusBar,
@@ -101,7 +102,7 @@
 
   void SimpleViewerApplication::OnStudyListReceived(const OrthancApiClient::JsonResponseReadyMessage& message)
   {
-    const Json::Value& response = message.Response;
+    const Json::Value& response = message.GetJson();
 
     if (response.isArray() && response.size() > 1)
     {
@@ -110,7 +111,7 @@
   }
   void SimpleViewerApplication::OnStudyReceived(const OrthancApiClient::JsonResponseReadyMessage& message)
   {
-    const Json::Value& response = message.Response;
+    const Json::Value& response = message.GetJson();
 
     if (response.isObject() && response["Series"].isArray())
     {
@@ -123,7 +124,7 @@
 
   void SimpleViewerApplication::OnSeriesReceived(const OrthancApiClient::JsonResponseReadyMessage& message)
   {
-    const Json::Value& response = message.Response;
+    const Json::Value& response = message.GetJson();
 
     if (response.isObject() && response["Instances"].isArray() && response["Instances"].size() > 0)
     {
@@ -166,7 +167,7 @@
 
   void SimpleViewerApplication::OnWidgetGeometryChanged(const LayerWidget::GeometryChangedMessage& message)
   {
-    message.origin_.FitContent();
+    message.GetOrigin().FitContent();
   }
 
   void SimpleViewerApplication::SelectSeriesInMainViewport(const std::string& seriesId)
--- a/Applications/Samples/SimpleViewerApplicationSingleFile.h	Mon Nov 05 13:25:03 2018 +0100
+++ b/Applications/Samples/SimpleViewerApplicationSingleFile.h	Mon Nov 05 16:18:27 2018 +0100
@@ -44,8 +44,8 @@
   namespace Samples
   {
     class SimpleViewerApplication :
-        public SampleSingleCanvasWithButtonsApplicationBase,
-        public IObserver
+      public SampleSingleCanvasWithButtonsApplicationBase,
+      public IObserver
     {
     private:
       class ThumbnailInteractor : public IWorldSceneInteractor
@@ -169,20 +169,20 @@
         {
           switch (keyChar)
           {
-          case 's':
-            widget.FitContent();
-            break;
+            case 's':
+              widget.FitContent();
+              break;
 
-          case 'l':
-            application_.currentTool_ = Tools_LineMeasure;
-            break;
+            case 'l':
+              application_.currentTool_ = Tools_LineMeasure;
+              break;
 
-          case 'c':
-            application_.currentTool_ = Tools_CircleMeasure;
-            break;
+            case 'c':
+              application_.currentTool_ = Tools_CircleMeasure;
+              break;
 
-          default:
-            break;
+            default:
+              break;
           }
         }
       };
@@ -196,7 +196,7 @@
       public:
         SimpleViewerApplicationAdapter(MessageBroker& broker, SimpleViewerApplication& application)
           : WasmPlatformApplicationAdapter(broker, application),
-          viewerApplication_(application)
+            viewerApplication_(application)
         {
 
         }
@@ -264,9 +264,9 @@
       {
         boost::program_options::options_description generic("Sample options");
         generic.add_options()
-            ("studyId", boost::program_options::value<std::string>(),
-             "Orthanc ID of the study")
-            ;
+          ("studyId", boost::program_options::value<std::string>(),
+           "Orthanc ID of the study")
+          ;
 
         options.add(generic);
       }
@@ -319,7 +319,9 @@
         if (parameters.count("studyId") < 1)
         {
           LOG(WARNING) << "The study ID is missing, will take the first studyId found in Orthanc";
-          orthancApiClient_->GetJsonAsync("/studies", new Callable<SimpleViewerApplication, OrthancApiClient::JsonResponseReadyMessage>(*this, &SimpleViewerApplication::OnStudyListReceived));
+          orthancApiClient_->GetJsonAsync("/studies",
+                                          new Callable<SimpleViewerApplication, OrthancApiClient::JsonResponseReadyMessage>
+                                          (*this, &SimpleViewerApplication::OnStudyListReceived));
         }
         else
         {
@@ -329,7 +331,7 @@
 
       void OnStudyListReceived(const OrthancApiClient::JsonResponseReadyMessage& message)
       {
-        const Json::Value& response = message.Response;
+        const Json::Value& response = message.GetJson();
 
         if (response.isArray() && response.size() > 1)
         {
@@ -338,22 +340,26 @@
       }
       void OnStudyReceived(const OrthancApiClient::JsonResponseReadyMessage& message)
       {
-        const Json::Value& response = message.Response;
+        const Json::Value& response = message.GetJson();
 
         if (response.isObject() && response["Series"].isArray())
         {
           for (size_t i=0; i < response["Series"].size(); i++)
           {
-            orthancApiClient_->GetJsonAsync("/series/" + response["Series"][(int)i].asString(), new Callable<SimpleViewerApplication, OrthancApiClient::JsonResponseReadyMessage>(*this, &SimpleViewerApplication::OnSeriesReceived));
+            orthancApiClient_->GetJsonAsync("/series/" + response["Series"][(int)i].asString(),
+                                            new Callable<SimpleViewerApplication, OrthancApiClient::JsonResponseReadyMessage>
+                                            (*this, &SimpleViewerApplication::OnSeriesReceived));
           }
         }
       }
 
       void OnSeriesReceived(const OrthancApiClient::JsonResponseReadyMessage& message)
       {
-        const Json::Value& response = message.Response;
+        const Json::Value& response = message.GetJson();
 
-        if (response.isObject() && response["Instances"].isArray() && response["Instances"].size() > 0)
+        if (response.isObject() &&
+            response["Instances"].isArray() &&
+            response["Instances"].size() > 0)
         {
           // keep track of all instances IDs
           const std::string& seriesId = response["ID"].asString();
@@ -395,7 +401,7 @@
 
       void OnWidgetGeometryChanged(const LayerWidget::GeometryChangedMessage& message)
       {
-        message.origin_.FitContent();
+        message.GetOrigin().FitContent();
       }
 
       void SelectSeriesInMainViewport(const std::string& seriesId)
@@ -417,8 +423,8 @@
       virtual void GetButtonNames(std::string& pushButton1,
                                   std::string& pushButton2,
                                   std::string& tool1,
-                                  std::string& tool2
-                                  ) {
+                                  std::string& tool2)
+      {
         tool1 = "line";
         tool2 = "circle";
         pushButton1 = "action1";
@@ -426,8 +432,8 @@
       }
 
 #if ORTHANC_ENABLE_WASM==1
-      virtual void InitializeWasm() {
-
+      virtual void InitializeWasm()
+      {
         AttachWidgetToWasmViewport("canvas", thumbnailsLayout_);
         AttachWidgetToWasmViewport("canvas2", mainWidget_);
       }
--- a/Applications/Samples/SingleFrameApplication.h	Mon Nov 05 13:25:03 2018 +0100
+++ b/Applications/Samples/SingleFrameApplication.h	Mon Nov 05 16:18:27 2018 +0100
@@ -187,7 +187,7 @@
         // Once the geometry of the series is downloaded from Orthanc,
         // display its middle slice, and adapt the viewport to fit this
         // slice
-        if (source_ == &message.origin_)
+        if (source_ == &message.GetOrigin())
         {
           SetSlice(source_->GetSliceCount() / 2);
         }
--- a/Applications/Samples/SingleFrameEditorApplication.h	Mon Nov 05 13:25:03 2018 +0100
+++ b/Applications/Samples/SingleFrameEditorApplication.h	Mon Nov 05 16:18:27 2018 +0100
@@ -1164,17 +1164,17 @@
     
     void OnTagsReceived(const OrthancApiClient::BinaryResponseReadyMessage& message)
     {
-      size_t index = dynamic_cast<Orthanc::SingleValueObject<size_t>*>(message.Payload.get())->GetValue();
-
-      LOG(INFO) << "JSON received: " << message.Uri.c_str()
-                << " (" << message.AnswerSize << " bytes) for bitmap " << index;
+      size_t index = dynamic_cast<const Orthanc::SingleValueObject<size_t>&>(message.GetPayload()).GetValue();
+
+      LOG(INFO) << "JSON received: " << message.GetUri().c_str()
+                << " (" << message.GetAnswerSize() << " bytes) for bitmap " << index;
       
       Bitmaps::iterator bitmap = bitmaps_.find(index);
       if (bitmap != bitmaps_.end())
       {
         assert(bitmap->second != NULL);
         
-        OrthancPlugins::FullOrthancDataset dicom(message.Answer, message.AnswerSize);
+        OrthancPlugins::FullOrthancDataset dicom(message.GetAnswer(), message.GetAnswerSize());
         dynamic_cast<DicomBitmap*>(bitmap->second)->SetDicomTags(dicom);
 
         float c, w;
@@ -1193,10 +1193,10 @@
 
     void OnFrameReceived(const OrthancApiClient::BinaryResponseReadyMessage& message)
     {
-      size_t index = dynamic_cast<Orthanc::SingleValueObject<size_t>*>(message.Payload.get())->GetValue();
+      size_t index = dynamic_cast<const Orthanc::SingleValueObject<size_t>&>(message.GetPayload()).GetValue();
       
-      LOG(INFO) << "DICOM frame received: " << message.Uri.c_str()
-                << " (" << message.AnswerSize << " bytes) for bitmap " << index;
+      LOG(INFO) << "DICOM frame received: " << message.GetUri().c_str()
+                << " (" << message.GetAnswerSize() << " bytes) for bitmap " << index;
       
       Bitmaps::iterator bitmap = bitmaps_.find(index);
       if (bitmap != bitmaps_.end())
@@ -1204,9 +1204,9 @@
         assert(bitmap->second != NULL);
 
         std::string content;
-        if (message.AnswerSize > 0)
+        if (message.GetAnswerSize() > 0)
         {
-          content.assign(reinterpret_cast<const char*>(message.Answer), message.AnswerSize);
+          content.assign(reinterpret_cast<const char*>(message.GetAnswer()), message.GetAnswerSize());
         }
         
         std::auto_ptr<Orthanc::PamReader> reader(new Orthanc::PamReader);
@@ -2823,7 +2823,7 @@
     void OnDicomExported(const OrthancApiClient::JsonResponseReadyMessage& message)
     {
       LOG(WARNING) << "DICOM export was successful:"
-                   << message.Response.toStyledString();
+                   << message.GetJson().toStyledString();
     }
   };
 
--- a/Framework/Layers/OrthancFrameLayerSource.cpp	Mon Nov 05 13:25:03 2018 +0100
+++ b/Framework/Layers/OrthancFrameLayerSource.cpp	Mon Nov 05 16:18:27 2018 +0100
@@ -34,7 +34,7 @@
 
   void OrthancFrameLayerSource::OnSliceGeometryReady(const OrthancSlicesLoader::SliceGeometryReadyMessage& message)
   {
-    if (message.origin_.GetSliceCount() > 0)
+    if (message.GetOrigin().GetSliceCount() > 0)
     {
       LayerSourceBase::NotifyGeometryReady();
     }
--- a/Framework/Messages/IMessage.h	Mon Nov 05 13:25:03 2018 +0100
+++ b/Framework/Messages/IMessage.h	Mon Nov 05 16:18:27 2018 +0100
@@ -29,59 +29,79 @@
 
 
   // base message that are exchanged between IObservable and IObserver
-  struct IMessage : public boost::noncopyable
+  class IMessage : public boost::noncopyable
   {
+  private:
     int messageType_;
+    
   protected:
-    IMessage(const int& messageType)
-      : messageType_(messageType)
-    {}
+    IMessage(const int& messageType) :
+      messageType_(messageType)
+    {
+    }
+    
   public:
-    virtual ~IMessage() {}
+    virtual ~IMessage()
+    {
+    }
 
-    virtual int GetType() const {return messageType_;}
+    virtual int GetType() const
+    {
+      return messageType_;
+    }
   };
 
 
   // base class to derive from to implement your own messages
   // it handles the message type for you
   template <int type>
-  struct BaseMessage : public IMessage
+  class BaseMessage : public IMessage
   {
+  public:
     enum
     {
       Type = type
     };
 
-    BaseMessage()
-      : IMessage(static_cast<int>(Type))
-    {}
+    BaseMessage() :
+      IMessage(static_cast<int>(Type))
+    {
+    }
   };
+  
 
   // simple message implementation when no payload is needed
   // sample usage:
   // typedef NoPayloadMessage<MessageType_LayerSource_GeometryReady> GeometryReadyMessage;
   template <int type>
-  struct NoPayloadMessage : public BaseMessage<type>
+  class NoPayloadMessage : public BaseMessage<type>
   {
-    NoPayloadMessage()
-      : BaseMessage<type>()
-    {}
-
+  public:
+    NoPayloadMessage() :
+      BaseMessage<type>()
+    {
+    }
   };
 
   // simple message implementation when no payload is needed but the origin is required
   // sample usage:
   // typedef OriginMessage<MessageType_SliceLoader_GeometryError, OrthancSlicesLoader> SliceGeometryErrorMessage;
   template <int type, typename TOrigin>
-  struct OriginMessage : public BaseMessage<type>
+  class OriginMessage : public BaseMessage<type>
   {
+  private:
     TOrigin& origin_;
-    OriginMessage(TOrigin& origin)
-      : BaseMessage<type>(),
-        origin_(origin)
-    {}
 
-  };
+  public:
+    OriginMessage(TOrigin& origin) :
+      BaseMessage<type>(),
+      origin_(origin)
+    {
+    }
 
+    TOrigin& GetOrigin() const
+    {
+      return origin_;
+    }
+  };
 }
--- a/Framework/SmartLoader.cpp	Mon Nov 05 13:25:03 2018 +0100
+++ b/Framework/SmartLoader.cpp	Mon Nov 05 16:18:27 2018 +0100
@@ -206,7 +206,7 @@
 
   void SmartLoader::OnLayerGeometryReady(const ILayerSource::GeometryReadyMessage& message)
   {
-    OrthancFrameLayerSource& source = dynamic_cast<OrthancFrameLayerSource&>(message.origin_);
+    OrthancFrameLayerSource& source = dynamic_cast<OrthancFrameLayerSource&>(message.GetOrigin());
 
     // save/replace the slice in cache
     const Slice& slice = source.GetSlice(0); // TODO handle GetSliceCount()
@@ -229,7 +229,7 @@
 
   void SmartLoader::OnImageReady(const ILayerSource::ImageReadyMessage& message)
   {
-    OrthancFrameLayerSource& source = dynamic_cast<OrthancFrameLayerSource&>(message.origin_);
+    OrthancFrameLayerSource& source = dynamic_cast<OrthancFrameLayerSource&>(message.GetOrigin());
 
     // save/replace the slice in cache
     const Slice& slice = source.GetSlice(0); // TODO handle GetSliceCount() ?
@@ -253,7 +253,7 @@
 
   void SmartLoader::OnLayerReady(const ILayerSource::LayerReadyMessage& message)
   {
-    OrthancFrameLayerSource& source = dynamic_cast<OrthancFrameLayerSource&>(message.origin_);
+    OrthancFrameLayerSource& source = dynamic_cast<OrthancFrameLayerSource&>(message.GetOrigin());
     const Slice& slice = source.GetSlice(0); // TODO handle GetSliceCount() ?
     std::string sliceKeyId = (slice.GetOrthancInstanceId() + ":" + 
                               boost::lexical_cast<std::string>(slice.GetFrame()));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Toolbox/IWebService.cpp	Mon Nov 05 16:18:27 2018 +0100
@@ -0,0 +1,55 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * 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
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "IWebService.h"
+
+#include <Core/OrthancException.h>
+
+
+namespace OrthancStone
+{
+  const Orthanc::IDynamicObject&
+  IWebService::HttpRequestSuccessMessage::GetPayload() const
+  {
+    if (HasPayload())
+    {
+      return *payload_;
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+  }
+    
+
+  const Orthanc::IDynamicObject&
+  IWebService::HttpRequestErrorMessage::GetPayload() const
+  {
+    if (HasPayload())
+    {
+      return *payload_;
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+  }
+}
--- a/Framework/Toolbox/IWebService.h	Mon Nov 05 13:25:03 2018 +0100
+++ b/Framework/Toolbox/IWebService.h	Mon Nov 05 16:18:27 2018 +0100
@@ -21,12 +21,14 @@
 
 #pragma once
 
-#include <Core/IDynamicObject.h>
 #include "../../Framework/Messages/IObserver.h"
 #include "../../Framework/Messages/ICallable.h"
+
+#include <Core/IDynamicObject.h>
+#include <Core/Logging.h>
+
 #include <string>
 #include <map>
-#include <Core/Logging.h>
 
 namespace OrthancStone
 {
@@ -35,56 +37,110 @@
   // in a WASM environment, the WebService is asynchronous, the IWebservice
   // also implements an asynchronous interface: you must schedule a request
   // and you'll be notified when the response/error is ready.
-  class IWebService
+  class IWebService : public boost::noncopyable
   {
   protected:
     MessageBroker& broker_;
+    
   public:
     typedef std::map<std::string, std::string> Headers;
 
-    struct HttpRequestSuccessMessage: public BaseMessage<MessageType_HttpRequestSuccess>
+    class HttpRequestSuccessMessage : public BaseMessage<MessageType_HttpRequestSuccess>
     {
-      const std::string& uri_;
-      const void* answer_;
-      size_t answerSize_;
-      Orthanc::IDynamicObject* payload_;
+    private:
+      const std::string&             uri_;
+      const void*                    answer_;
+      size_t                         answerSize_;
+      const Orthanc::IDynamicObject* payload_;
+
+    public:
       HttpRequestSuccessMessage(const std::string& uri,
                                 const void* answer,
                                 size_t answerSize,
-                                Orthanc::IDynamicObject* payload)
-        : BaseMessage(),
-          uri_(uri),
-          answer_(answer),
-          answerSize_(answerSize),
-          payload_(payload)
-      {}
-    };
+                                const Orthanc::IDynamicObject* payload) :
+        uri_(uri),
+        answer_(answer),
+        answerSize_(answerSize),
+        payload_(payload)
+      {
+      }
+
+      const std::string& GetUri() const
+      {
+        return uri_;
+      }
+
+      const void* GetAnswer() const
+      {
+        return answer_;
+      }
+
+      size_t GetAnswerSize() const
+      {
+        return answerSize_;
+      }
+
+      bool HasPayload() const
+      {
+        return payload_ != NULL;
+      }
+
+      const Orthanc::IDynamicObject& GetPayload() const;
 
-    struct HttpRequestErrorMessage: public BaseMessage<MessageType_HttpRequestError>
+      const Orthanc::IDynamicObject* GetPayloadPointer() const
+      {
+        return payload_;
+      }
+    };
+    
+
+    class HttpRequestErrorMessage : public BaseMessage<MessageType_HttpRequestError>
     {
-      const std::string& uri_;
-      Orthanc::IDynamicObject* payload_;
+    private:
+      const std::string&              uri_;
+      const Orthanc::IDynamicObject*  payload_;
+
+    public:
       HttpRequestErrorMessage(const std::string& uri,
-                              Orthanc::IDynamicObject* payload)
-        : BaseMessage(),
-          uri_(uri),
-          payload_(payload)
-      {}
+                              const Orthanc::IDynamicObject* payload) :
+        uri_(uri),
+        payload_(payload)
+      {
+      }
+
+      const std::string& GetUri() const
+      {
+        return uri_;
+      }
+
+      bool HasPayload() const
+      {
+        return payload_ != NULL;
+      }
+
+      const Orthanc::IDynamicObject& GetPayload() const;
+
+      const Orthanc::IDynamicObject* GetPayloadPointer() const
+      {
+        return payload_;
+      }
     };
 
 
+    IWebService(MessageBroker& broker) :
+      broker_(broker)
+    {
+    }
 
-    IWebService(MessageBroker& broker)
-      : broker_(broker)
-    {}
-
+    
     virtual ~IWebService()
     {
     }
 
+    
     virtual void GetAsync(const std::string& uri,
                           const Headers& headers,
-                          Orthanc::IDynamicObject* payload,
+                          Orthanc::IDynamicObject* payload  /* takes ownership */,
                           MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
                           MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
                           unsigned int timeoutInSeconds = 60) = 0;
@@ -92,14 +148,14 @@
     virtual void PostAsync(const std::string& uri,
                            const Headers& headers,
                            const std::string& body,
-                           Orthanc::IDynamicObject* payload,
+                           Orthanc::IDynamicObject* payload  /* takes ownership */,
                            MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
                            MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
                            unsigned int timeoutInSeconds = 60) = 0;
 
     virtual void DeleteAsync(const std::string& uri,
                              const Headers& headers,
-                             Orthanc::IDynamicObject* payload,
+                             Orthanc::IDynamicObject* payload  /* takes ownership */,
                              MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
                              MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
                              unsigned int timeoutInSeconds = 60) = 0;
--- a/Framework/Toolbox/OrthancApiClient.cpp	Mon Nov 05 13:25:03 2018 +0100
+++ b/Framework/Toolbox/OrthancApiClient.cpp	Mon Nov 05 16:18:27 2018 +0100
@@ -21,14 +21,67 @@
 #include "OrthancApiClient.h"
 
 #include "MessagingToolbox.h"
-#include <Core/OrthancException.h>
 #include "Framework/Toolbox/MessagingToolbox.h"
 
-namespace OrthancStone {
+#include <Core/OrthancException.h>
 
-  OrthancApiClient::OrthancApiClient(MessageBroker &broker, IWebService &orthanc)
-    : IObservable(broker),
-      orthanc_(orthanc)
+namespace OrthancStone
+{
+  const Orthanc::IDynamicObject& OrthancApiClient::JsonResponseReadyMessage::GetPayload() const
+  {
+    if (HasPayload())
+    {
+      return *payload_;
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+  }
+  
+  
+  const Orthanc::IDynamicObject& OrthancApiClient::BinaryResponseReadyMessage::GetPayload() const
+  {
+    if (HasPayload())
+    {
+      return *payload_;
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+  }
+  
+  
+  const Orthanc::IDynamicObject& OrthancApiClient::EmptyResponseReadyMessage::GetPayload() const
+  {
+    if (HasPayload())
+    {
+      return *payload_;
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+  }
+  
+  
+  const Orthanc::IDynamicObject& OrthancApiClient::HttpErrorMessage::GetPayload() const
+  {
+    if (HasPayload())
+    {
+      return *payload_;
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+  }
+  
+  
+  OrthancApiClient::OrthancApiClient(MessageBroker &broker, IWebService &orthanc) :
+    IObservable(broker),
+    orthanc_(orthanc)
   {
   }
 
@@ -54,16 +107,18 @@
     void ConvertResponseToJson(const IWebService::HttpRequestSuccessMessage& message)
     {
       Json::Value response;
-      if (MessagingToolbox::ParseJson(response, message.answer_, message.answerSize_))
+      if (MessagingToolbox::ParseJson(response, message.GetAnswer(), message.GetAnswerSize()))
       {
         if (orthancApiSuccessCallback_.get() != NULL)
         {
-          orthancApiSuccessCallback_->Apply(OrthancApiClient::JsonResponseReadyMessage(message.uri_, response, message.payload_));
+          orthancApiSuccessCallback_->Apply(OrthancApiClient::JsonResponseReadyMessage
+                                            (message.GetUri(), response, message.GetPayloadPointer()));
         }
       }
       else if (orthancApiFailureCallback_.get() != NULL)
       {
-        orthancApiFailureCallback_->Apply(OrthancApiClient::HttpErrorMessage(message.uri_, message.payload_));
+        orthancApiFailureCallback_->Apply(OrthancApiClient::HttpErrorMessage
+                                          (message.GetUri(), message.GetPayloadPointer()));
       }
 
       delete this; // hack untill we find someone to take ownership of this object (https://isocpp.org/wiki/faq/freestore-mgmt#delete-this)
@@ -73,7 +128,7 @@
     {
       if (orthancApiFailureCallback_.get() != NULL)
       {
-        orthancApiFailureCallback_->Apply(OrthancApiClient::HttpErrorMessage(message.uri_));
+        orthancApiFailureCallback_->Apply(OrthancApiClient::HttpErrorMessage(message.GetUri(), message.GetPayloadPointer()));
       }
 
       delete this; // hack untill we find someone to take ownership of this object (https://isocpp.org/wiki/faq/freestore-mgmt#delete-this)
@@ -103,11 +158,14 @@
     {
       if (orthancApiSuccessCallback_.get() != NULL)
       {
-        orthancApiSuccessCallback_->Apply(OrthancApiClient::BinaryResponseReadyMessage(message.uri_, message.answer_, message.answerSize_, message.payload_));
+        orthancApiSuccessCallback_->Apply(OrthancApiClient::BinaryResponseReadyMessage
+                                          (message.GetUri(), message.GetAnswer(),
+                                           message.GetAnswerSize(), message.GetPayloadPointer()));
       }
       else if (orthancApiFailureCallback_.get() != NULL)
       {
-        orthancApiFailureCallback_->Apply(OrthancApiClient::HttpErrorMessage(message.uri_, message.payload_));
+        orthancApiFailureCallback_->Apply(OrthancApiClient::HttpErrorMessage
+                                          (message.GetUri(), message.GetPayloadPointer()));
       }
 
       delete this; // hack untill we find someone to take ownership of this object (https://isocpp.org/wiki/faq/freestore-mgmt#delete-this)
@@ -117,7 +175,7 @@
     {
       if (orthancApiFailureCallback_.get() != NULL)
       {
-        orthancApiFailureCallback_->Apply(OrthancApiClient::HttpErrorMessage(message.uri_));
+        orthancApiFailureCallback_->Apply(OrthancApiClient::HttpErrorMessage(message.GetUri(), message.GetPayloadPointer()));
       }
 
       delete this; // hack untill we find someone to take ownership of this object (https://isocpp.org/wiki/faq/freestore-mgmt#delete-this)
@@ -147,11 +205,13 @@
     {
       if (orthancApiSuccessCallback_.get() != NULL)
       {
-        orthancApiSuccessCallback_->Apply(OrthancApiClient::EmptyResponseReadyMessage(message.uri_, message.payload_));
+        orthancApiSuccessCallback_->Apply(OrthancApiClient::EmptyResponseReadyMessage
+                                          (message.GetUri(), message.GetPayloadPointer()));
       }
       else if (orthancApiFailureCallback_.get() != NULL)
       {
-        orthancApiFailureCallback_->Apply(OrthancApiClient::HttpErrorMessage(message.uri_, message.payload_));
+        orthancApiFailureCallback_->Apply(OrthancApiClient::HttpErrorMessage
+                                          (message.GetUri(), message.GetPayloadPointer()));
       }
 
       delete this; // hack untill we find someone to take ownership of this object (https://isocpp.org/wiki/faq/freestore-mgmt#delete-this)
@@ -161,7 +221,7 @@
     {
       if (orthancApiFailureCallback_.get() != NULL)
       {
-        orthancApiFailureCallback_->Apply(OrthancApiClient::HttpErrorMessage(message.uri_));
+        orthancApiFailureCallback_->Apply(OrthancApiClient::HttpErrorMessage(message.GetUri(), message.GetPayloadPointer()));
       }
 
       delete this; // hack untill we find someone to take ownership of this object (https://isocpp.org/wiki/faq/freestore-mgmt#delete-this)
--- a/Framework/Toolbox/OrthancApiClient.h	Mon Nov 05 13:25:03 2018 +0100
+++ b/Framework/Toolbox/OrthancApiClient.h	Mon Nov 05 16:18:27 2018 +0100
@@ -30,105 +30,168 @@
 
 namespace OrthancStone
 {
-  class OrthancApiClient:
-      public IObservable
+  class OrthancApiClient : public IObservable
   {
   public:
-
-    struct JsonResponseReadyMessage : public BaseMessage<MessageType_OrthancApi_GenericGetJson_Ready>
+    class JsonResponseReadyMessage : public BaseMessage<MessageType_OrthancApi_GenericGetJson_Ready>
     {
-      Json::Value   Response;
-      std::string   Uri;
-      std::auto_ptr<Orthanc::IDynamicObject>  Payload;
+    private:
+      const std::string&              uri_;
+      const Json::Value&              json_;
+      const Orthanc::IDynamicObject*  payload_;
 
+    public:
       JsonResponseReadyMessage(const std::string& uri,
-                               const Json::Value& response,
-                               Orthanc::IDynamicObject*  payload = NULL)
-        : BaseMessage(),
-          Response(response),
-          Uri(uri),
-          Payload(payload)
+                               const Json::Value& json,
+                               const Orthanc::IDynamicObject* payload) :
+        uri_(uri),
+        json_(json),
+        payload_(payload)
       {
       }
-    };
 
-    struct EmptyResponseReadyMessage : public BaseMessage<MessageType_OrthancApi_GenericEmptyResponse_Ready>
-    {
-      std::string   Uri;
-      std::auto_ptr<Orthanc::IDynamicObject>  Payload;
+      const std::string& GetUri() const
+      {
+        return uri_;
+      }
+
+      const Json::Value& GetJson() const
+      {
+        return json_;
+      }
 
-      EmptyResponseReadyMessage(const std::string& uri,
-                                Orthanc::IDynamicObject*  payload = NULL)
-        : BaseMessage(),
-          Uri(uri),
-          Payload(payload)
+      bool HasPayload() const
       {
+        return payload_ != NULL;
       }
+
+      const Orthanc::IDynamicObject& GetPayload() const;
     };
+    
 
-    struct HttpErrorMessage : public BaseMessage<MessageType_OrthancApi_GenericHttpError_Ready>
+    class BinaryResponseReadyMessage : public BaseMessage<MessageType_OrthancApi_GenericGetBinary_Ready>
     {
-      std::string   Uri;
-      std::auto_ptr<Orthanc::IDynamicObject>  Payload;
+    private:
+      const std::string&              uri_;
+      const void*                     answer_;
+      size_t                          answerSize_;
+      const Orthanc::IDynamicObject*  payload_;
 
-      HttpErrorMessage(const std::string& uri,
-                       Orthanc::IDynamicObject*  payload = NULL)
-        : BaseMessage(),
-          Uri(uri),
-          Payload(payload)
-      {
-      }
-    };
-
-    struct BinaryResponseReadyMessage : public BaseMessage<MessageType_OrthancApi_GenericGetBinary_Ready>
-    {
-      const void* Answer;
-      size_t AnswerSize;
-      std::string   Uri;
-      std::auto_ptr<Orthanc::IDynamicObject>  Payload;
-
+    public:
       BinaryResponseReadyMessage(const std::string& uri,
                                  const void* answer,
                                  size_t answerSize,
-                                 Orthanc::IDynamicObject*  payload = NULL)
-        : BaseMessage(),
-          Answer(answer),
-          AnswerSize(answerSize),
-          Uri(uri),
-          Payload(payload)
+                                 const Orthanc::IDynamicObject* payload) :
+        uri_(uri),
+        answer_(answer),
+        answerSize_(answerSize),
+        payload_(payload)
       {
       }
+
+      const std::string& GetUri() const
+      {
+        return uri_;
+      }
+
+      const void* GetAnswer() const
+      {
+        return answer_;
+      }
+
+      size_t GetAnswerSize() const
+      {
+        return answerSize_;
+      }
+
+      bool HasPayload() const
+      {
+        return payload_ != NULL;
+      }
+
+      const Orthanc::IDynamicObject& GetPayload() const;
     };
 
 
+    class EmptyResponseReadyMessage : public BaseMessage<MessageType_OrthancApi_GenericEmptyResponse_Ready>
+    {
+    private:
+      const std::string&              uri_;
+      const Orthanc::IDynamicObject*  payload_;
 
-  public:
+    public:
+      EmptyResponseReadyMessage(const std::string& uri,
+                                const Orthanc::IDynamicObject* payload) :
+        uri_(uri),
+        payload_(payload)
+      {
+      }
+
+      const std::string& GetUri() const
+      {
+        return uri_;
+      }
+
+      bool HasPayload() const
+      {
+        return payload_ != NULL;
+      }
+
+      const Orthanc::IDynamicObject& GetPayload() const;
+    };
 
-    enum Mode
+    
+    class HttpErrorMessage : public BaseMessage<MessageType_OrthancApi_GenericHttpError_Ready>
     {
-      Mode_GetJson
+    private:
+      const std::string&              uri_;
+      const Orthanc::IDynamicObject*  payload_;
+
+    public:
+      HttpErrorMessage(const std::string& uri,
+                       const Orthanc::IDynamicObject* payload) :
+        uri_(uri),
+        payload_(payload)
+      {
+      }
+
+      const std::string& GetUri() const
+      {
+        return uri_;
+      }
+
+      bool HasPayload() const
+      {
+        return payload_ != NULL;
+      }
+
+      const Orthanc::IDynamicObject& GetPayload() const;
     };
 
+
   protected:
     IWebService&                      orthanc_;
 
   public:
     OrthancApiClient(MessageBroker& broker,
                      IWebService& orthanc);
-    virtual ~OrthancApiClient() {}
+    
+    virtual ~OrthancApiClient()
+    {
+    }
 
     // schedule a GET request expecting a JSON response.
     void GetJsonAsync(const std::string& uri,
                       MessageHandler<JsonResponseReadyMessage>* successCallback,
                       MessageHandler<HttpErrorMessage>* failureCallback = NULL,
-                      Orthanc::IDynamicObject* payload = NULL);
+                      Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
 
     // schedule a GET request expecting a binary response.
     void GetBinaryAsync(const std::string& uri,
                         const std::string& contentType,
                         MessageHandler<BinaryResponseReadyMessage>* successCallback,
                         MessageHandler<HttpErrorMessage>* failureCallback = NULL,
-                        Orthanc::IDynamicObject* payload = NULL)
+                        Orthanc::IDynamicObject* payload = NULL   /* takes ownership */)
     {
       IWebService::Headers headers;
       headers["Accept"] = contentType;
@@ -140,27 +203,27 @@
                         const IWebService::Headers& headers,
                         MessageHandler<BinaryResponseReadyMessage>* successCallback,
                         MessageHandler<HttpErrorMessage>* failureCallback = NULL,
-                        Orthanc::IDynamicObject* payload = NULL);
+                        Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
 
     // schedule a POST request expecting a JSON response.
     void PostBinaryAsyncExpectJson(const std::string& uri,
                                    const std::string& body,
                                    MessageHandler<JsonResponseReadyMessage>* successCallback,
                                    MessageHandler<HttpErrorMessage>* failureCallback = NULL,
-                                   Orthanc::IDynamicObject* payload = NULL);
+                                   Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
 
     // schedule a POST request expecting a JSON response.
     void PostJsonAsyncExpectJson(const std::string& uri,
                                  const Json::Value& data,
                                  MessageHandler<JsonResponseReadyMessage>* successCallback,
                                  MessageHandler<HttpErrorMessage>* failureCallback = NULL,
-                                 Orthanc::IDynamicObject* payload = NULL);
+                                 Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
 
     // schedule a DELETE request expecting an empty response.
     void DeleteAsync(const std::string& uri,
                      MessageHandler<EmptyResponseReadyMessage>* successCallback,
                      MessageHandler<HttpErrorMessage>* failureCallback = NULL,
-                     Orthanc::IDynamicObject* payload = NULL);
+                     Orthanc::IDynamicObject* payload = NULL   /* takes ownership */);
 
 
   };
--- a/Framework/Toolbox/OrthancSlicesLoader.cpp	Mon Nov 05 13:25:03 2018 +0100
+++ b/Framework/Toolbox/OrthancSlicesLoader.cpp	Mon Nov 05 16:18:27 2018 +0100
@@ -232,13 +232,13 @@
 
   void OrthancSlicesLoader::OnSliceImageError(const OrthancApiClient::HttpErrorMessage& message)
   {
-    NotifySliceImageError(dynamic_cast<const Operation&>(*(message.Payload)));
+    NotifySliceImageError(dynamic_cast<const Operation&>(message.GetPayload()));
     state_ = State_Error;
   }
 
   void OrthancSlicesLoader::ParseSeriesGeometry(const OrthancApiClient::JsonResponseReadyMessage& message)
   {
-    Json::Value series = message.Response;
+    const Json::Value& series = message.GetJson();
     Json::Value::Members instances = series.getMemberNames();
     
     slices_.Reserve(instances.size());
@@ -275,8 +275,8 @@
   
   void OrthancSlicesLoader::ParseInstanceGeometry(const OrthancApiClient::JsonResponseReadyMessage& message)
   {
-    Json::Value tags = message.Response;
-    const std::string& instanceId = dynamic_cast<OrthancSlicesLoader::Operation*>(message.Payload.get())->GetInstanceId();
+    const Json::Value& tags = message.GetJson();
+    const std::string& instanceId = dynamic_cast<const OrthancSlicesLoader::Operation&>(message.GetPayload()).GetInstanceId();
 
     OrthancPlugins::FullOrthancDataset dataset(tags);
     
@@ -312,9 +312,9 @@
   
   void OrthancSlicesLoader::ParseFrameGeometry(const OrthancApiClient::JsonResponseReadyMessage& message)
   {
-    Json::Value tags = message.Response;
-    const std::string& instanceId = dynamic_cast<OrthancSlicesLoader::Operation*>(message.Payload.get())->GetInstanceId();
-    unsigned int frame = dynamic_cast<OrthancSlicesLoader::Operation*>(message.Payload.get())->GetFrame();
+    const Json::Value& tags = message.GetJson();
+    const std::string& instanceId = dynamic_cast<const OrthancSlicesLoader::Operation&>(message.GetPayload()).GetInstanceId();
+    unsigned int frame = dynamic_cast<const OrthancSlicesLoader::Operation&>(message.GetPayload()).GetFrame();
 
     OrthancPlugins::FullOrthancDataset dataset(tags);
     
@@ -340,13 +340,13 @@
   
   void OrthancSlicesLoader::ParseSliceImagePng(const OrthancApiClient::BinaryResponseReadyMessage& message)
   {
-    const Operation& operation = dynamic_cast<const OrthancSlicesLoader::Operation&>(*message.Payload.get());
+    const Operation& operation = dynamic_cast<const OrthancSlicesLoader::Operation&>(message.GetPayload());
     boost::shared_ptr<Orthanc::ImageAccessor>  image;
     
     try
     {
       image.reset(new Orthanc::PngReader);
-      dynamic_cast<Orthanc::PngReader&>(*image).ReadFromMemory(message.Answer, message.AnswerSize);
+      dynamic_cast<Orthanc::PngReader&>(*image).ReadFromMemory(message.GetAnswer(), message.GetAnswerSize());
     }
     catch (Orthanc::OrthancException&)
     {
@@ -380,13 +380,13 @@
   
   void OrthancSlicesLoader::ParseSliceImagePam(const OrthancApiClient::BinaryResponseReadyMessage& message)
   {
-    const Operation& operation = dynamic_cast<const OrthancSlicesLoader::Operation&>(*message.Payload.get());
+    const Operation& operation = dynamic_cast<const OrthancSlicesLoader::Operation&>(message.GetPayload());
     boost::shared_ptr<Orthanc::ImageAccessor>  image;
 
     try
     {
       image.reset(new Orthanc::PamReader);
-      dynamic_cast<Orthanc::PamReader&>(*image).ReadFromMemory(std::string(reinterpret_cast<const char*>(message.Answer), message.AnswerSize));
+      dynamic_cast<Orthanc::PamReader&>(*image).ReadFromMemory(std::string(reinterpret_cast<const char*>(message.GetAnswer()), message.GetAnswerSize()));
     }
     catch (Orthanc::OrthancException&)
     {
@@ -421,9 +421,9 @@
 
   void OrthancSlicesLoader::ParseSliceImageJpeg(const OrthancApiClient::JsonResponseReadyMessage& message)
   {
-    const Operation& operation = dynamic_cast<const OrthancSlicesLoader::Operation&>(*message.Payload.get());
+    const Operation& operation = dynamic_cast<const OrthancSlicesLoader::Operation&>(message.GetPayload());
 
-    Json::Value encoded = message.Response;
+    const Json::Value& encoded = message.GetJson();
     if (encoded.type() != Json::objectValue ||
         !encoded.isMember("Orthanc") ||
         encoded["Orthanc"].type() != Json::objectValue)
@@ -432,7 +432,7 @@
       return;
     }
     
-    Json::Value& info = encoded["Orthanc"];
+    const Json::Value& info = encoded["Orthanc"];
     if (!info.isMember("PixelData") ||
         !info.isMember("Stretched") ||
         !info.isMember("Compression") ||
@@ -593,11 +593,11 @@
   
   void OrthancSlicesLoader::ParseSliceRawImage(const OrthancApiClient::BinaryResponseReadyMessage& message)
   {
-    const Operation& operation = dynamic_cast<const OrthancSlicesLoader::Operation&>(*message.Payload.get());
+    const Operation& operation = dynamic_cast<const OrthancSlicesLoader::Operation&>(message.GetPayload());
     Orthanc::GzipCompressor compressor;
     
     std::string raw;
-    compressor.Uncompress(raw, message.Answer, message.AnswerSize);
+    compressor.Uncompress(raw, message.GetAnswer(), message.GetAnswerSize());
     
     const Orthanc::DicomImageInformation& info = operation.GetSlice().GetImageInformation();
     
--- a/Framework/Volumes/StructureSetLoader.cpp	Mon Nov 05 13:25:03 2018 +0100
+++ b/Framework/Volumes/StructureSetLoader.cpp	Mon Nov 05 16:18:27 2018 +0100
@@ -37,7 +37,7 @@
 
   void StructureSetLoader::OnReferencedSliceLoaded(const OrthancApiClient::JsonResponseReadyMessage& message)
   {
-    OrthancPlugins::FullOrthancDataset dataset(message.Response);
+    OrthancPlugins::FullOrthancDataset dataset(message.GetJson());
 
     Orthanc::DicomMap slice;
     MessagingToolbox::ConvertDataset(slice, dataset);
@@ -48,7 +48,7 @@
 
   void StructureSetLoader::OnStructureSetLoaded(const OrthancApiClient::JsonResponseReadyMessage& message)
   {
-    OrthancPlugins::FullOrthancDataset dataset(message.Response);
+    OrthancPlugins::FullOrthancDataset dataset(message.GetJson());
     structureSet_.reset(new DicomStructureSet(dataset));
 
     std::set<std::string> instances;
@@ -66,7 +66,7 @@
 
   void StructureSetLoader::OnLookupCompleted(const OrthancApiClient::JsonResponseReadyMessage& message)
   {
-    Json::Value lookup = message.Response;
+    const Json::Value& lookup = message.GetJson();
 
     if (lookup.type() != Json::arrayValue ||
         lookup.size() != 1 ||
--- a/Framework/Widgets/LayerWidget.cpp	Mon Nov 05 13:25:03 2018 +0100
+++ b/Framework/Widgets/LayerWidget.cpp	Mon Nov 05 16:18:27 2018 +0100
@@ -519,7 +519,7 @@
   void LayerWidget::OnGeometryReady(const ILayerSource::GeometryReadyMessage& message)
   {
     size_t i;
-    if (LookupLayer(i, message.origin_))
+    if (LookupLayer(i, message.GetOrigin()))
     {
       LOG(INFO) << ": Geometry ready for layer " << i << " in " << GetName();
 
@@ -558,7 +558,7 @@
   void LayerWidget::OnContentChanged(const ILayerSource::ContentChangedMessage& message)
   {
     size_t index;
-    if (LookupLayer(index, message.origin_))
+    if (LookupLayer(index, message.GetOrigin()))
     {
       InvalidateLayer(index);
     }
@@ -571,7 +571,7 @@
     if (message.slice_.ContainsPlane(slice_))
     {
       size_t index;
-      if (LookupLayer(index, message.origin_))
+      if (LookupLayer(index, message.GetOrigin()))
       {
         InvalidateLayer(index);
       }
@@ -583,7 +583,7 @@
   void LayerWidget::OnLayerReady(const ILayerSource::LayerReadyMessage& message)
   {
     size_t index;
-    if (LookupLayer(index, message.origin_))
+    if (LookupLayer(index, message.GetOrigin()))
     {
       if (message.isError_)
       {
--- a/Platforms/Generic/OracleWebService.h	Mon Nov 05 13:25:03 2018 +0100
+++ b/Platforms/Generic/OracleWebService.h	Mon Nov 05 16:18:27 2018 +0100
@@ -82,16 +82,5 @@
     {
       oracle_.Submit(new WebServiceDeleteCommand(broker_, successCallback, failureCallback, parameters_, uri, headers, timeoutInSeconds, payload, context_));
     }
-
-
-    void Start()
-    {
-      oracle_.Start();
-    }
-
-    void Stop()
-    {
-      oracle_.Stop();
-    }
   };
 }
--- a/Platforms/Generic/WebServiceCommandBase.cpp	Mon Nov 05 13:25:03 2018 +0100
+++ b/Platforms/Generic/WebServiceCommandBase.cpp	Mon Nov 05 16:18:27 2018 +0100
@@ -49,17 +49,20 @@
 
   void WebServiceCommandBase::Commit()
   {
-    NativeStoneApplicationContext::GlobalMutexLocker lock(context_);  // we want to make sure that, i.e, the UpdateThread is not triggered while we are updating the "model" with the result of a WebServiceCommand
+    // We want to make sure that, i.e, the UpdateThread is not
+    // triggered while we are updating the "model" with the result of
+    // a WebServiceCommand
+    NativeStoneApplicationContext::GlobalMutexLocker lock(context_); 
 
     if (success_ && successCallback_.get() != NULL)
     {
-      successCallback_->Apply(IWebService::HttpRequestSuccessMessage(uri_, answer_.c_str(), answer_.size(), payload_.release()));
+      IWebService::HttpRequestSuccessMessage message(uri_, answer_.c_str(), answer_.size(), payload_.get());
+      successCallback_->Apply(message);
     }
     else if (!success_ && failureCallback_.get() != NULL)
     {
-      failureCallback_->Apply(IWebService::HttpRequestErrorMessage(uri_, payload_.release()));
+      IWebService::HttpRequestErrorMessage message(uri_, payload_.get());
+      failureCallback_->Apply(message);
     }
-
   }
-
 }
--- a/Resources/CMake/OrthancStoneConfiguration.cmake	Mon Nov 05 13:25:03 2018 +0100
+++ b/Resources/CMake/OrthancStoneConfiguration.cmake	Mon Nov 05 16:18:27 2018 +0100
@@ -258,6 +258,7 @@
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/Extent2D.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/FiniteProjectiveCamera.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/GeometryToolbox.cpp
+  ${ORTHANC_STONE_ROOT}/Framework/Toolbox/IWebService.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/IWebService.h
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ImageGeometry.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Toolbox/LinearAlgebra.cpp