changeset 1089:998d9e4402e0 broker

integration mainline->broker
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 23 Oct 2019 11:04:47 +0200
parents fe723ea10d98 (diff) b8521df3944a (current diff)
children 71c2dc28a85b
files Applications/Samples/SingleFrameEditorApplication.h Resources/CMake/OrthancStoneConfiguration.cmake
diffstat 132 files changed, 1127 insertions(+), 1540 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/Generic/NativeStoneApplicationContext.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Applications/Generic/NativeStoneApplicationContext.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -24,10 +24,10 @@
 
 namespace OrthancStone
 {
-  Deprecated::IWidget& NativeStoneApplicationContext::GlobalMutexLocker::SetCentralWidget(Deprecated::IWidget* widget)
+  void NativeStoneApplicationContext::GlobalMutexLocker::SetCentralWidget(
+    boost::shared_ptr<Deprecated::IWidget> widget)
   {
     that_.centralViewport_.SetCentralWidget(widget);
-    return *widget;
   }
 
 
@@ -45,9 +45,7 @@
   }
   
 
-  NativeStoneApplicationContext::NativeStoneApplicationContext(MessageBroker& broker) :
-    StoneApplicationContext(broker),
-    centralViewport_(broker),
+  NativeStoneApplicationContext::NativeStoneApplicationContext() :
     stopped_(true),
     updateDelayInMs_(100)   // By default, 100ms between each refresh of the content
   {
--- a/Applications/Generic/NativeStoneApplicationContext.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Applications/Generic/NativeStoneApplicationContext.h	Wed Oct 23 11:04:47 2019 +0200
@@ -56,7 +56,7 @@
       {
       }
 
-      Deprecated::IWidget& SetCentralWidget(Deprecated::IWidget* widget);   // Takes ownership
+      void SetCentralWidget(boost::shared_ptr<Deprecated::IWidget> widget);
 
       Deprecated::IViewport& GetCentralViewport() 
       {
@@ -67,14 +67,9 @@
       {
         that_.updateDelayInMs_ = delayInMs;
       }
-
-      MessageBroker& GetMessageBroker()
-      {
-        return that_.GetMessageBroker();
-      }
     };
 
-    NativeStoneApplicationContext(MessageBroker& broker);
+    NativeStoneApplicationContext();
 
     void Start();
 
--- a/Applications/Generic/NativeStoneApplicationRunner.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Applications/Generic/NativeStoneApplicationRunner.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -97,7 +97,7 @@
     DeclareCommandLineOptions(options);
     
     // application specific options
-    application_.DeclareStartupOptions(options);
+    application_->DeclareStartupOptions(options);
 
     boost::program_options::variables_map parameters;
     bool error = false;
@@ -197,7 +197,7 @@
 
       LogStatusBar statusBar;
 
-      NativeStoneApplicationContext context(broker_);
+      NativeStoneApplicationContext context;
 
       {
         // use multiple threads to execute asynchronous tasks like 
@@ -206,24 +206,23 @@
         oracle.Start();
 
         {
-          Deprecated::OracleWebService webService(
-            broker_, oracle, webServiceParameters, context);
-          
+          boost::shared_ptr<Deprecated::OracleWebService> webService
+            (new Deprecated::OracleWebService(oracle, webServiceParameters, context));
           context.SetWebService(webService);
           context.SetOrthancBaseUrl(webServiceParameters.GetUrl());
 
-          Deprecated::OracleDelayedCallExecutor delayedExecutor(broker_, oracle, context);
+          Deprecated::OracleDelayedCallExecutor delayedExecutor(oracle, context);
           context.SetDelayedCallExecutor(delayedExecutor);
 
-          application_.Initialize(&context, statusBar, parameters);
+          application_->Initialize(&context, statusBar, parameters);
 
           {
             NativeStoneApplicationContext::GlobalMutexLocker locker(context);
-            locker.SetCentralWidget(application_.GetCentralWidget());
+            locker.SetCentralWidget(application_->GetCentralWidget());
             locker.GetCentralViewport().SetStatusBar(statusBar);
           }
 
-          std::string title = application_.GetTitle();
+          std::string title = application_->GetTitle();
           if (title.empty())
           {
             title = "Stone of Orthanc";
@@ -244,7 +243,7 @@
       }
 
       LOG(WARNING) << "The application is stopping";
-      application_.Finalize();
+      application_->Finalize();
     }
     catch (Orthanc::OrthancException& e)
     {
--- a/Applications/Generic/NativeStoneApplicationRunner.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Applications/Generic/NativeStoneApplicationRunner.h	Wed Oct 23 11:04:47 2019 +0200
@@ -34,14 +34,11 @@
   class NativeStoneApplicationRunner
   {
   protected:
-    MessageBroker&      broker_;
-    IStoneApplication&  application_;
+    boost::shared_ptr<IStoneApplication>  application_;
+    
   public:
-
-    NativeStoneApplicationRunner(MessageBroker& broker,
-                                 IStoneApplication& application)
-      : broker_(broker),
-        application_(application)
+    NativeStoneApplicationRunner(boost::shared_ptr<IStoneApplication> application)
+      : application_(application)
     {
     }
     int Execute(int argc,
--- a/Applications/IStoneApplication.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Applications/IStoneApplication.h	Wed Oct 23 11:04:47 2019 +0200
@@ -64,7 +64,11 @@
 #endif
 
     virtual std::string GetTitle() const = 0;
-    virtual Deprecated::IWidget* GetCentralWidget() = 0;
+    
+    virtual void SetCentralWidget(boost::shared_ptr<Deprecated::IWidget> widget) = 0;
+    
+    virtual boost::shared_ptr<Deprecated::IWidget> GetCentralWidget() = 0;
+    
     virtual void Finalize() = 0;
   };
 }
--- a/Applications/Samples/SampleApplicationBase.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Applications/Samples/SampleApplicationBase.h	Wed Oct 23 11:04:47 2019 +0200
@@ -40,9 +40,8 @@
   {
     class SampleApplicationBase : public IStoneApplication
     {
-    protected:
-      // ownership is transferred to the application context
-      Deprecated::WorldSceneWidget*  mainWidget_;
+    private:
+      boost::shared_ptr<Deprecated::IWidget>  mainWidget_;
 
     public:
       virtual void Initialize(StoneApplicationContext* context,
@@ -64,7 +63,16 @@
 
 
       virtual void Finalize() ORTHANC_OVERRIDE {}
-      virtual Deprecated::IWidget* GetCentralWidget() ORTHANC_OVERRIDE {return mainWidget_;}
+
+      virtual void SetCentralWidget(boost::shared_ptr<Deprecated::IWidget> widget) ORTHANC_OVERRIDE
+      {
+        mainWidget_ = widget;
+      }
+
+      virtual boost::shared_ptr<Deprecated::IWidget> GetCentralWidget() ORTHANC_OVERRIDE
+      {
+        return mainWidget_;
+      }
 
 #if ORTHANC_ENABLE_WASM==1
       // default implementations for a single canvas named "canvas" in the HTML and an emtpy WasmApplicationAdapter
--- a/Applications/Samples/SampleMainNative.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Applications/Samples/SampleMainNative.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -26,19 +26,18 @@
 #if ORTHANC_ENABLE_QT==1
 #include "Qt/SampleQtApplicationRunner.h"
 #endif
-#include "../../Framework/Messages/MessageBroker.h"
 
 int main(int argc, char* argv[]) 
 {
-  OrthancStone::MessageBroker broker;
-  SampleApplication sampleStoneApplication(broker);
+  boost::shared_ptr<SampleApplication> sampleStoneApplication(new SampleApplication);
 
 #if ORTHANC_ENABLE_SDL==1
-  OrthancStone::SdlStoneApplicationRunner sdlApplicationRunner(broker, sampleStoneApplication);
+  OrthancStone::SdlStoneApplicationRunner sdlApplicationRunner(sampleStoneApplication);
   return sdlApplicationRunner.Execute(argc, argv);
 #endif
+  
 #if ORTHANC_ENABLE_QT==1
-  OrthancStone::Samples::SampleQtApplicationRunner qtAppRunner(broker, sampleStoneApplication);
+  OrthancStone::Samples::SampleQtApplicationRunner qtAppRunner(sampleStoneApplication);
   return qtAppRunner.Execute(argc, argv);
 #endif
 }
--- a/Applications/Samples/SimpleViewerApplicationSingleFile.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Applications/Samples/SimpleViewerApplicationSingleFile.h	Wed Oct 23 11:04:47 2019 +0200
@@ -44,7 +44,7 @@
   {
     class SimpleViewerApplication :
       public SampleSingleCanvasWithButtonsApplicationBase,
-      public IObserver
+      public ObserverBase<SimpleViewerApplication>
     {
     private:
       class ThumbnailInteractor : public Deprecated::IWorldSceneInteractor
@@ -199,8 +199,8 @@
         SimpleViewerApplication&  viewerApplication_;
 
       public:
-        SimpleViewerApplicationAdapter(MessageBroker& broker, SimpleViewerApplication& application)
-          : WasmPlatformApplicationAdapter(broker, application),
+        SimpleViewerApplicationAdapter(SimpleViewerApplication& application)
+          : WasmPlatformApplicationAdapter(application),
             viewerApplication_(application)
         {
         }
@@ -243,7 +243,7 @@
       std::auto_ptr<ThumbnailInteractor>   thumbnailInteractor_;
       Deprecated::LayoutWidget*                        mainLayout_;
       Deprecated::LayoutWidget*                        thumbnailsLayout_;
-      std::vector<Deprecated::SliceViewerWidget*>      thumbnails_;
+      std::vector<boost::shared_ptr<Deprecated::SliceViewerWidget> >      thumbnails_;
 
       std::map<std::string, std::vector<std::string> > instancesIdsPerSeriesId_;
       std::map<std::string, Json::Value> seriesTags_;
@@ -258,8 +258,7 @@
       Orthanc::Font                        font_;
 
     public:
-      SimpleViewerApplication(MessageBroker& broker) :
-        IObserver(broker),
+      SimpleViewerApplication() :
         currentTool_(Tool_LineMeasure),
         mainLayout_(NULL),
         currentInstanceIndex_(0),
@@ -297,26 +296,28 @@
           mainLayout_->SetBackgroundColor(0, 0, 0);
           mainLayout_->SetHorizontal();
 
-          thumbnailsLayout_ = new Deprecated::LayoutWidget("thumbnail-layout");
+          boost::shared_ptr<Deprecated::LayoutWidget> thumbnailsLayout_(new Deprecated::LayoutWidget("thumbnail-layout"));
           thumbnailsLayout_->SetPadding(10);
           thumbnailsLayout_->SetBackgroundCleared(true);
           thumbnailsLayout_->SetBackgroundColor(50, 50, 50);
           thumbnailsLayout_->SetVertical();
 
-          mainWidget_ = new Deprecated::SliceViewerWidget(GetBroker(), "main-viewport");
+          boost::shared_ptr<Deprecated::SliceViewerWidget> widget
+            (new Deprecated::SliceViewerWidget("main-viewport"));
+          SetCentralWidget(widget);
           //mainWidget_->RegisterObserver(*this);
 
           // hierarchy
           mainLayout_->AddWidget(thumbnailsLayout_);
-          mainLayout_->AddWidget(mainWidget_);
+          mainLayout_->AddWidget(widget);
 
           // sources
-          smartLoader_.reset(new Deprecated::SmartLoader(GetBroker(), context->GetOrthancApiClient()));
+          smartLoader_.reset(new Deprecated::SmartLoader(context->GetOrthancApiClient()));
           smartLoader_->SetImageQuality(Deprecated::SliceImageQuality_FullPam);
 
           mainLayout_->SetTransmitMouseOver(true);
           mainWidgetInteractor_.reset(new MainWidgetInteractor(*this));
-          mainWidget_->SetInteractor(*mainWidgetInteractor_);
+          widget->SetInteractor(*mainWidgetInteractor_);
           thumbnailInteractor_.reset(new ThumbnailInteractor(*this));
         }
 
@@ -327,10 +328,10 @@
         if (parameters.count("studyId") < 1)
         {
           LOG(WARNING) << "The study ID is missing, will take the first studyId found in Orthanc";
-          context->GetOrthancApiClient().GetJsonAsync(
+          context->GetOrthancApiClient()->GetJsonAsync(
             "/studies",
             new Callable<SimpleViewerApplication, Deprecated::OrthancApiClient::JsonResponseReadyMessage>
-            (*this, &SimpleViewerApplication::OnStudyListReceived));
+            (GetSharedObserver(), &SimpleViewerApplication::OnStudyListReceived));
         }
         else
         {
@@ -357,10 +358,10 @@
         {
           for (size_t i=0; i < response["Series"].size(); i++)
           {
-            context_->GetOrthancApiClient().GetJsonAsync(
+            context_->GetOrthancApiClient()->GetJsonAsync(
               "/series/" + response["Series"][(int)i].asString(),
               new Callable<SimpleViewerApplication, Deprecated::OrthancApiClient::JsonResponseReadyMessage>
-              (*this, &SimpleViewerApplication::OnSeriesReceived));
+              (GetSharedObserver(), &SimpleViewerApplication::OnSeriesReceived));
           }
         }
       }
@@ -387,7 +388,7 @@
           LoadThumbnailForSeries(seriesId, instancesIdsPerSeriesId_[seriesId][0]);
 
           // if this is the first thumbnail loaded, load the first instance in the mainWidget
-          Deprecated::SliceViewerWidget& widget = *dynamic_cast<Deprecated::SliceViewerWidget*>(mainWidget_);
+          Deprecated::SliceViewerWidget& widget = dynamic_cast<Deprecated::SliceViewerWidget&>(*GetCentralWidget());
           if (widget.GetLayerCount() == 0)
           {
             smartLoader_->SetFrameInWidget(widget, 0, instancesIdsPerSeriesId_[seriesId][0], 0);
@@ -398,10 +399,10 @@
       void LoadThumbnailForSeries(const std::string& seriesId, const std::string& instanceId)
       {
         LOG(INFO) << "Loading thumbnail for series " << seriesId;
-        Deprecated::SliceViewerWidget* thumbnailWidget = new Deprecated::SliceViewerWidget(GetBroker(), "thumbnail-series-" + seriesId);
+        boost::shared_ptr<Deprecated::SliceViewerWidget> thumbnailWidget(new Deprecated::SliceViewerWidget("thumbnail-series-" + seriesId));
         thumbnails_.push_back(thumbnailWidget);
         thumbnailsLayout_->AddWidget(thumbnailWidget);
-        thumbnailWidget->RegisterObserverCallback(new Callable<SimpleViewerApplication, Deprecated::SliceViewerWidget::GeometryChangedMessage>(*this, &SimpleViewerApplication::OnWidgetGeometryChanged));
+        Register<Deprecated::SliceViewerWidget::GeometryChangedMessage>(*thumbnailWidget, &SimpleViewerApplication::OnWidgetGeometryChanged);
         smartLoader_->SetFrameInWidget(*thumbnailWidget, 0, instanceId, 0);
         thumbnailWidget->SetInteractor(*thumbnailInteractor_);
       }
@@ -409,9 +410,9 @@
       void SelectStudy(const std::string& studyId)
       {
         LOG(INFO) << "Selecting study: " << studyId;
-        context_->GetOrthancApiClient().GetJsonAsync(
+        context_->GetOrthancApiClient()->GetJsonAsync(
           "/studies/" + studyId, new Callable<SimpleViewerApplication, Deprecated::OrthancApiClient::JsonResponseReadyMessage>
-          (*this, &SimpleViewerApplication::OnStudyReceived));
+          (GetSharedObserver(), &SimpleViewerApplication::OnStudyReceived));
       }
 
       void OnWidgetGeometryChanged(const Deprecated::SliceViewerWidget::GeometryChangedMessage& message)
@@ -422,7 +423,7 @@
 
       void SelectSeriesInMainViewport(const std::string& seriesId)
       {
-        Deprecated::SliceViewerWidget& widget = *dynamic_cast<Deprecated::SliceViewerWidget*>(mainWidget_);
+        Deprecated::SliceViewerWidget& widget = dynamic_cast<Deprecated::SliceViewerWidget&>(*GetCentralWidget());
         smartLoader_->SetFrameInWidget(widget, 0, instancesIdsPerSeriesId_[seriesId][0], 0);
       }
 
@@ -451,7 +452,7 @@
       virtual void InitializeWasm()
       {
         AttachWidgetToWasmViewport("canvas", thumbnailsLayout_);
-        AttachWidgetToWasmViewport("canvas2", mainWidget_);
+        AttachWidgetToWasmViewport("canvas2", widget);
       }
 #endif
 
--- a/Applications/Samples/SingleFrameApplication.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Applications/Samples/SingleFrameApplication.h	Wed Oct 23 11:04:47 2019 +0200
@@ -38,7 +38,7 @@
   {
     class SingleFrameApplication :
       public SampleSingleCanvasApplicationBase,
-      public IObserver
+      public ObserverBase<SingleFrameApplication>
     {
     private:
       class Interactor : public Deprecated::IWorldSceneInteractor
@@ -127,7 +127,7 @@
 
       void OffsetSlice(int offset)
       {
-        if (source_ != NULL)
+        if (source_)
         {
           int slice = static_cast<int>(slice_) + offset;
 
@@ -149,21 +149,15 @@
       }
 
 
-      Deprecated::SliceViewerWidget& GetMainWidget()
-      {
-        return *dynamic_cast<Deprecated::SliceViewerWidget*>(mainWidget_);
-      }
-      
-
       void SetSlice(size_t index)
       {
-        if (source_ != NULL &&
+        if (source_ &&
             index < source_->GetSlicesCount())
         {
           slice_ = static_cast<unsigned int>(index);
           
 #if 1
-          GetMainWidget().SetSlice(source_->GetSlice(slice_).GetGeometry());
+          widget_->SetSlice(source_->GetSlice(slice_).GetGeometry());
 #else
           // TEST for scene extents - Rotate the axes
           double a = 15.0 / 180.0 * boost::math::constants::pi<double>();
@@ -189,22 +183,22 @@
         // 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.GetOrigin())
+        if (source_ &&
+            source_.get() == &message.GetOrigin())
         {
           SetSlice(source_->GetSlicesCount() / 2);
         }
 
-        GetMainWidget().FitContent();
+        widget_->FitContent();
       }
-      
+
+      boost::shared_ptr<Deprecated::SliceViewerWidget>  widget_;
       std::auto_ptr<Interactor>         mainWidgetInteractor_;
-      const Deprecated::DicomSeriesVolumeSlicer*    source_;
+      boost::shared_ptr<Deprecated::DicomSeriesVolumeSlicer> source_;
       unsigned int                      slice_;
 
     public:
-      SingleFrameApplication(MessageBroker& broker) :
-        IObserver(broker),
-        source_(NULL),
+      SingleFrameApplication() :
         slice_(0)
       {
       }
@@ -243,13 +237,15 @@
         std::string instance = parameters["instance"].as<std::string>();
         int frame = parameters["frame"].as<unsigned int>();
 
-        mainWidget_ = new Deprecated::SliceViewerWidget(GetBroker(), "main-widget");
+        widget_.reset(new Deprecated::SliceViewerWidget("main-widget"));
+        SetCentralWidget(widget_);
 
-        std::auto_ptr<Deprecated::DicomSeriesVolumeSlicer> layer(new Deprecated::DicomSeriesVolumeSlicer(GetBroker(), context->GetOrthancApiClient()));
-        source_ = layer.get();
+        boost::shared_ptr<Deprecated::DicomSeriesVolumeSlicer> layer(new Deprecated::DicomSeriesVolumeSlicer);
+        layer->Connect(context->GetOrthancApiClient());
+        source_ = layer;
         layer->LoadFrame(instance, frame);
-        layer->RegisterObserverCallback(new Callable<SingleFrameApplication, Deprecated::IVolumeSlicer::GeometryReadyMessage>(*this, &SingleFrameApplication::OnMainWidgetGeometryReady));
-        GetMainWidget().AddLayer(layer.release());
+        Register<Deprecated::IVolumeSlicer::GeometryReadyMessage>(*layer, &SingleFrameApplication::OnMainWidgetGeometryReady);
+        widget_->AddLayer(layer);
 
         Deprecated::RenderStyle s;
 
@@ -258,11 +254,11 @@
           s.interpolation_ = ImageInterpolation_Bilinear;
         }
 
-        GetMainWidget().SetLayerStyle(0, s);
-        GetMainWidget().SetTransmitMouseOver(true);
+        widget_->SetLayerStyle(0, s);
+        widget_->SetTransmitMouseOver(true);
 
         mainWidgetInteractor_.reset(new Interactor(*this));
-        GetMainWidget().SetInteractor(*mainWidgetInteractor_);
+        widget_->SetInteractor(*mainWidgetInteractor_);
       }
     };
 
--- a/Applications/Samples/SingleFrameEditorApplication.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Applications/Samples/SingleFrameEditorApplication.h	Wed Oct 23 11:04:47 2019 +0200
@@ -28,15 +28,14 @@
 #include "../../Framework/Radiography/RadiographyLayerMoveTracker.h"
 #include "../../Framework/Radiography/RadiographyLayerResizeTracker.h"
 #include "../../Framework/Radiography/RadiographyLayerRotateTracker.h"
+#include "../../Framework/Radiography/RadiographyMaskLayer.h"
 #include "../../Framework/Radiography/RadiographyScene.h"
 #include "../../Framework/Radiography/RadiographySceneCommand.h"
+#include "../../Framework/Radiography/RadiographySceneReader.h"
+#include "../../Framework/Radiography/RadiographySceneWriter.h"
 #include "../../Framework/Radiography/RadiographyWidget.h"
 #include "../../Framework/Radiography/RadiographyWindowingTracker.h"
-#include "../../Framework/Radiography/RadiographySceneWriter.h"
-#include "../../Framework/Radiography/RadiographySceneReader.h"
-#include "../../Framework/Radiography/RadiographyMaskLayer.h"
-
-#include <../../Framework/Toolbox/TextRenderer.h>
+#include "../../Framework/Toolbox/TextRenderer.h"
 
 #include <Core/HttpClient.h>
 #include <Core/Images/FontRegistry.h>
@@ -57,7 +56,7 @@
   {
     class RadiographyEditorInteractor :
         public Deprecated::IWorldSceneInteractor,
-        public IObserver
+        public ObserverBase<RadiographyEditorInteractor>
     {
     private:
       enum Tool
@@ -84,8 +83,7 @@
 
 
     public:
-      RadiographyEditorInteractor(MessageBroker& broker) :
-        IObserver(broker),
+      RadiographyEditorInteractor() :
         context_(NULL),
         tool_(Tool_Move),
         maskLayer_(NULL)
@@ -317,7 +315,7 @@
           LOG(INFO) << "JSON export was successful: "
                     << snapshot.toStyledString();
 
-          boost::shared_ptr<RadiographyScene> scene(new RadiographyScene(GetBroker()));
+          boost::shared_ptr<RadiographyScene> scene(new RadiographyScene);
           RadiographySceneReader reader(*scene, context_->GetOrthancApiClient());
 
           Orthanc::FontRegistry fontRegistry;
@@ -353,7 +351,7 @@
 
           if (context_ != NULL)
           {
-            widget.GetScene().ExportDicom(context_->GetOrthancApiClient(),
+            widget.GetScene().ExportDicom(*context_->GetOrthancApiClient(),
                                           tags, std::string(), 0.1, 0.1, widget.IsInverted(),
                                           widget.GetInterpolation(), EXPORT_USING_PAM);
           }
@@ -437,12 +435,6 @@
       RadiographyMaskLayer*                 maskLayer_;
 
     public:
-      SingleFrameEditorApplication(MessageBroker& broker) :
-        IObserver(broker),
-        interactor_(broker)
-      {
-      }
-
       virtual ~SingleFrameEditorApplication()
       {
         LOG(WARNING) << "Destroying the application";
@@ -496,9 +488,9 @@
 
         fontRegistry_.AddFromResource(Orthanc::EmbeddedResources::FONT_UBUNTU_MONO_BOLD_16);
         
-        scene_.reset(new RadiographyScene(GetBroker()));
+        scene_.reset(new RadiographyScene);
         
-        RadiographyLayer& dicomLayer = scene_->LoadDicomFrame(context->GetOrthancApiClient(), instance, 0, false, NULL);
+        RadiographyLayer& dicomLayer = scene_->LoadDicomFrame(*context->GetOrthancApiClient(), instance, 0, false, NULL);
         //scene_->LoadDicomFrame(instance, frame, false); //.SetPan(200, 0);
         // = scene_->LoadDicomFrame(context->GetOrthancApiClient(), "61f3143e-96f34791-ad6bbb8d-62559e75-45943e1b", 0, false, NULL);
 
@@ -535,10 +527,10 @@
           layer.SetPan(0, 200);
         }
         
-        
-        mainWidget_ = new RadiographyWidget(GetBroker(), scene_, "main-widget");
-        mainWidget_->SetTransmitMouseOver(true);
-        mainWidget_->SetInteractor(interactor_);
+        boost::shared_ptr<RadiographyWidget> widget(new RadiographyWidget(scene_, "main-widget"));
+        widget->SetTransmitMouseOver(true);
+        widget->SetInteractor(interactor_);
+        SetCentralWidget(widget);
 
         //scene_->SetWindowing(128, 256);
       }
--- a/Applications/Sdl/SdlEngine.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Applications/Sdl/SdlEngine.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -99,9 +99,7 @@
 
 
   SdlEngine::SdlEngine(SdlWindow& window,
-                       NativeStoneApplicationContext& context,
-                       MessageBroker& broker) :
-    IObserver(broker),
+                       NativeStoneApplicationContext& context) :
     window_(window),
     context_(context),
     surface_(window),
--- a/Applications/Sdl/SdlEngine.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Applications/Sdl/SdlEngine.h	Wed Oct 23 11:04:47 2019 +0200
@@ -23,12 +23,13 @@
 
 #if ORTHANC_ENABLE_SDL == 1
 
+#include "../../Framework/Messages/ObserverBase.h"
+#include "../Generic/NativeStoneApplicationContext.h"
 #include "SdlCairoSurface.h"
-#include "../Generic/NativeStoneApplicationContext.h"
 
 namespace OrthancStone
 {
-  class SdlEngine : public IObserver
+  class SdlEngine : public ObserverBase<SdlEngine>
   {
   private:
     SdlWindow&                window_;
@@ -46,8 +47,7 @@
 
   public:
     SdlEngine(SdlWindow& window,
-              NativeStoneApplicationContext& context,
-              MessageBroker& broker);
+              NativeStoneApplicationContext& context);
   
     void OnViewportChanged(const Deprecated::IViewport::ViewportChangedMessage& message)
     {
--- a/Applications/Sdl/SdlStoneApplicationRunner.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Applications/Sdl/SdlStoneApplicationRunner.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -103,20 +103,19 @@
     LOG(WARNING) << "Starting the application";
 
     SdlWindow window(title.c_str(), width_, height_, enableOpenGl_);
-    SdlEngine sdl(window, context, broker_);
+    boost::shared_ptr<SdlEngine> sdl(new SdlEngine(window, context));
 
     {
       NativeStoneApplicationContext::GlobalMutexLocker locker(context);
 
-      locker.GetCentralViewport().RegisterObserverCallback(
-        new Callable<SdlEngine, Deprecated::IViewport::ViewportChangedMessage>
-        (sdl, &SdlEngine::OnViewportChanged));
+      sdl->Register<Deprecated::IViewport::ViewportChangedMessage>
+        (locker.GetCentralViewport(), &SdlEngine::OnViewportChanged);
 
       //context.GetCentralViewport().Register(sdl);  // (*)
     }
 
     context.Start();
-    sdl.Run();
+    sdl->Run();
 
     LOG(WARNING) << "Stopping the application";
 
--- a/Applications/Sdl/SdlStoneApplicationRunner.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Applications/Sdl/SdlStoneApplicationRunner.h	Wed Oct 23 11:04:47 2019 +0200
@@ -39,9 +39,8 @@
     bool          enableOpenGl_;
     
   public:
-    SdlStoneApplicationRunner(MessageBroker& broker,
-                              IStoneApplication& application) :
-      NativeStoneApplicationRunner(broker, application)
+    SdlStoneApplicationRunner(boost::shared_ptr<IStoneApplication> application) :
+      NativeStoneApplicationRunner(application)
     {
     }
 
--- a/Applications/StoneApplicationContext.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Applications/StoneApplicationContext.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -32,35 +32,35 @@
       throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
     }
 
-    orthanc_.reset(new Deprecated::OrthancApiClient(broker_, *webService_, orthancBaseUrl_));
+    orthanc_.reset(new Deprecated::OrthancApiClient(*webService_, orthancBaseUrl_));
   }
 
 
-  Deprecated::IWebService& StoneApplicationContext::GetWebService()
+  boost::shared_ptr<Deprecated::IWebService> StoneApplicationContext::GetWebService()
   {
     if (webService_ == NULL)
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
     }
     
-    return *webService_;
+    return webService_;
   }
 
   
-  Deprecated::OrthancApiClient& StoneApplicationContext::GetOrthancApiClient()
+  boost::shared_ptr<Deprecated::OrthancApiClient> StoneApplicationContext::GetOrthancApiClient()
   {
     if (orthanc_.get() == NULL)
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
     }
     
-    return *orthanc_;
+    return orthanc_;
   }
 
   
-  void StoneApplicationContext::SetWebService(Deprecated::IWebService& webService)
+  void StoneApplicationContext::SetWebService(boost::shared_ptr<Deprecated::IWebService> webService)
   {
-    webService_ = &webService;
+    webService_ = webService;
     InitializeOrthanc();
   }
 
--- a/Applications/StoneApplicationContext.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Applications/StoneApplicationContext.h	Wed Oct 23 11:04:47 2019 +0200
@@ -59,18 +59,15 @@
   class StoneApplicationContext : public boost::noncopyable
   {
   private:
-    MessageBroker&                   broker_;
-    Deprecated::IWebService*         webService_;
-    Deprecated::IDelayedCallExecutor*            delayedCallExecutor_;
-    std::auto_ptr<Deprecated::OrthancApiClient>  orthanc_;
+    boost::shared_ptr<Deprecated::IWebService>     webService_;
+    Deprecated::IDelayedCallExecutor*  delayedCallExecutor_;   // TODO => shared_ptr ??
+    boost::shared_ptr<Deprecated::OrthancApiClient>  orthanc_;
     std::string                      orthancBaseUrl_;
 
     void InitializeOrthanc();
 
   public:
-    StoneApplicationContext(MessageBroker& broker) :
-      broker_(broker),
-      webService_(NULL),
+    StoneApplicationContext() :
       delayedCallExecutor_(NULL)
     {
     }
@@ -79,21 +76,11 @@
     {
     }
 
-    MessageBroker& GetMessageBroker()
-    {
-      return broker_;
-    }
+    boost::shared_ptr<Deprecated::IWebService> GetWebService();
 
-    bool HasWebService() const
-    {
-      return webService_ != NULL;
-    }
+    boost::shared_ptr<Deprecated::OrthancApiClient> GetOrthancApiClient();
 
-    Deprecated::IWebService& GetWebService();
-
-    Deprecated::OrthancApiClient& GetOrthancApiClient();
-
-    void SetWebService(Deprecated::IWebService& webService);
+    void SetWebService(boost::shared_ptr<Deprecated::IWebService> webService);
 
     void SetOrthancBaseUrl(const std::string& baseUrl);
 
--- a/Framework/Deprecated/Layers/DicomSeriesVolumeSlicer.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Deprecated/Layers/DicomSeriesVolumeSlicer.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -87,59 +87,73 @@
   }
 
 
-  DicomSeriesVolumeSlicer::DicomSeriesVolumeSlicer(OrthancStone::MessageBroker& broker,
-                                                   OrthancApiClient& orthanc) :
-    IVolumeSlicer(broker),
-    IObserver(broker),
-    loader_(broker, orthanc),
+  DicomSeriesVolumeSlicer::DicomSeriesVolumeSlicer() :
     quality_(SliceImageQuality_FullPng)
   {
-    loader_.RegisterObserverCallback(
-      new OrthancStone::Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceGeometryReadyMessage>
-        (*this, &DicomSeriesVolumeSlicer::OnSliceGeometryReady));
-
-    loader_.RegisterObserverCallback(
-      new OrthancStone::Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceGeometryErrorMessage>
-      (*this, &DicomSeriesVolumeSlicer::OnSliceGeometryError));
+  }
 
-    loader_.RegisterObserverCallback(
-      new OrthancStone::Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceImageReadyMessage>
-        (*this, &DicomSeriesVolumeSlicer::OnSliceImageReady));
-
-    loader_.RegisterObserverCallback(
-      new OrthancStone::Callable<DicomSeriesVolumeSlicer, OrthancSlicesLoader::SliceImageErrorMessage>
-      (*this, &DicomSeriesVolumeSlicer::OnSliceImageError));
+  void DicomSeriesVolumeSlicer::Connect(boost::shared_ptr<OrthancApiClient> orthanc)
+  {
+    loader_.reset(new OrthancSlicesLoader(orthanc));
+    Register<OrthancSlicesLoader::SliceGeometryReadyMessage>(*loader_, &DicomSeriesVolumeSlicer::OnSliceGeometryReady);
+    Register<OrthancSlicesLoader::SliceGeometryErrorMessage>(*loader_, &DicomSeriesVolumeSlicer::OnSliceGeometryError);
+    Register<OrthancSlicesLoader::SliceImageReadyMessage>(*loader_, &DicomSeriesVolumeSlicer::OnSliceImageReady);
+    Register<OrthancSlicesLoader::SliceImageErrorMessage>(*loader_, &DicomSeriesVolumeSlicer::OnSliceImageError);
   }
 
   
   void DicomSeriesVolumeSlicer::LoadSeries(const std::string& seriesId)
   {
-    loader_.ScheduleLoadSeries(seriesId);
+    if (loader_.get() == NULL)
+    {
+      // Should have called "Connect()"
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+    
+    loader_->ScheduleLoadSeries(seriesId);
   }
 
 
   void DicomSeriesVolumeSlicer::LoadInstance(const std::string& instanceId)
   {
-    loader_.ScheduleLoadInstance(instanceId);
+    if (loader_.get() == NULL)
+    {
+      // Should have called "Connect()"
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+    
+    loader_->ScheduleLoadInstance(instanceId);
   }
 
 
   void DicomSeriesVolumeSlicer::LoadFrame(const std::string& instanceId,
                                           unsigned int frame)
   {
-    loader_.ScheduleLoadFrame(instanceId, frame);
+    if (loader_.get() == NULL)
+    {
+      // Should have called "Connect()"
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+    
+    loader_->ScheduleLoadFrame(instanceId, frame);
   }
 
 
   bool DicomSeriesVolumeSlicer::GetExtent(std::vector<OrthancStone::Vector>& points,
                                           const OrthancStone::CoordinateSystem3D& viewportSlice)
   {
+    if (loader_.get() == NULL)
+    {
+      // Should have called "Connect()"
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+    
     size_t index;
 
-    if (loader_.IsGeometryReady() &&
-        loader_.LookupSlice(index, viewportSlice))
+    if (loader_->IsGeometryReady() &&
+        loader_->LookupSlice(index, viewportSlice))
     {
-      loader_.GetSlice(index).GetExtent(points);
+      loader_->GetSlice(index).GetExtent(points);
       return true;
     }
     else
@@ -151,12 +165,18 @@
   
   void DicomSeriesVolumeSlicer::ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice)
   {
+    if (loader_.get() == NULL)
+    {
+      // Should have called "Connect()"
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+    
     size_t index;
 
-    if (loader_.IsGeometryReady() &&
-        loader_.LookupSlice(index, viewportSlice))
+    if (loader_->IsGeometryReady() &&
+        loader_->LookupSlice(index, viewportSlice))
     {
-      loader_.ScheduleLoadSliceImage(index, quality_);
+      loader_->ScheduleLoadSliceImage(index, quality_);
     }
   }
 }
--- a/Framework/Deprecated/Layers/DicomSeriesVolumeSlicer.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Deprecated/Layers/DicomSeriesVolumeSlicer.h	Wed Oct 23 11:04:47 2019 +0200
@@ -22,6 +22,7 @@
 #pragma once
 
 #include "IVolumeSlicer.h"
+#include "../../Messages/ObserverBase.h"
 #include "../Toolbox/IWebService.h"
 #include "../Toolbox/OrthancSlicesLoader.h"
 #include "../Toolbox/OrthancApiClient.h"
@@ -33,7 +34,7 @@
   // messages are sent to observers so they can use it
   class DicomSeriesVolumeSlicer :
     public IVolumeSlicer,
-    public OrthancStone::IObserver
+    public OrthancStone::ObserverBase<DicomSeriesVolumeSlicer>
     //private OrthancSlicesLoader::ISliceLoaderObserver
   {
   public:
@@ -79,13 +80,14 @@
   private:
     class RendererFactory;
     
-    OrthancSlicesLoader  loader_;
+    boost::shared_ptr<OrthancSlicesLoader> loader_;
     SliceImageQuality    quality_;
 
   public:
-    DicomSeriesVolumeSlicer(OrthancStone::MessageBroker& broker,
-                            OrthancApiClient& orthanc);
+    DicomSeriesVolumeSlicer();
 
+    void Connect(boost::shared_ptr<OrthancApiClient> orthanc);
+    
     void LoadSeries(const std::string& seriesId);
 
     void LoadInstance(const std::string& instanceId);
@@ -105,12 +107,12 @@
 
     size_t GetSlicesCount() const
     {
-      return loader_.GetSlicesCount();
+      return loader_->GetSlicesCount();
     }
 
     const Slice& GetSlice(size_t slice) const 
     {
-      return loader_.GetSlice(slice);
+      return loader_->GetSlice(slice);
     }
 
     virtual bool GetExtent(std::vector<OrthancStone::Vector>& points,
--- a/Framework/Deprecated/Layers/DicomStructureSetSlicer.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Deprecated/Layers/DicomStructureSetSlicer.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -140,15 +140,10 @@
   };
   
 
-  DicomStructureSetSlicer::DicomStructureSetSlicer(OrthancStone::MessageBroker& broker,
-                                                   StructureSetLoader& loader) :
-    IVolumeSlicer(broker),
-    IObserver(broker),
+  DicomStructureSetSlicer::DicomStructureSetSlicer(StructureSetLoader& loader) :
     loader_(loader)
   {
-    loader_.RegisterObserverCallback(
-      new OrthancStone::Callable<DicomStructureSetSlicer, StructureSetLoader::ContentChangedMessage>
-      (*this, &DicomStructureSetSlicer::OnStructureSetLoaded));
+    Register<StructureSetLoader::ContentChangedMessage>(loader_, &DicomStructureSetSlicer::OnStructureSetLoaded);
   }
 
 
--- a/Framework/Deprecated/Layers/DicomStructureSetSlicer.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Deprecated/Layers/DicomStructureSetSlicer.h	Wed Oct 23 11:04:47 2019 +0200
@@ -28,7 +28,7 @@
 {
   class DicomStructureSetSlicer :
     public IVolumeSlicer,
-    public OrthancStone::IObserver
+    public OrthancStone::ObserverBase<DicomStructureSetSlicer>
   {
   private:
     class Renderer;
@@ -42,8 +42,7 @@
     }
 
   public:
-    DicomStructureSetSlicer(OrthancStone::MessageBroker& broker,
-                            StructureSetLoader& loader);
+    DicomStructureSetSlicer(StructureSetLoader& loader);
 
     virtual bool GetExtent(std::vector<OrthancStone::Vector>& points,
                            const OrthancStone::CoordinateSystem3D& viewportPlane)
--- a/Framework/Deprecated/Layers/IVolumeSlicer.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Deprecated/Layers/IVolumeSlicer.h	Wed Oct 23 11:04:47 2019 +0200
@@ -122,11 +122,6 @@
     };
 
 
-    IVolumeSlicer(OrthancStone::MessageBroker& broker) :
-      IObservable(broker)
-    {
-    }
-    
     virtual ~IVolumeSlicer()
     {
     }
--- a/Framework/Deprecated/SmartLoader.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Deprecated/SmartLoader.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -21,7 +21,6 @@
 
 #include "SmartLoader.h"
 
-#include "../Messages/MessageForwarder.h"
 #include "../StoneException.h"
 #include "Core/Images/Image.h"
 #include "Core/Logging.h"
@@ -68,11 +67,6 @@
     CachedSliceStatus               status_;
 
   public:
-    CachedSlice(OrthancStone::MessageBroker& broker) :
-    IVolumeSlicer(broker)
-    {
-    }
-
     virtual ~CachedSlice()
     {
     }
@@ -106,7 +100,7 @@
 
     CachedSlice* Clone() const
     {
-      CachedSlice* output = new CachedSlice(GetBroker());
+      CachedSlice* output = new CachedSlice;
       output->sliceIndex_ = sliceIndex_;
       output->slice_.reset(slice_->Clone());
       output->image_ = image_;
@@ -119,10 +113,7 @@
   };
 
 
-  SmartLoader::SmartLoader(OrthancStone::MessageBroker& broker,  
-                           OrthancApiClient& orthancApiClient) :
-    IObservable(broker),
-    IObserver(broker),
+  SmartLoader::SmartLoader(boost::shared_ptr<OrthancApiClient> orthancApiClient) :
     imageQuality_(SliceImageQuality_FullPam),
     orthancApiClient_(orthancApiClient)
   {
@@ -140,7 +131,7 @@
     //   the messages to its observables
     // in both cases, we must be carefull about objects lifecycle !!!
 
-    std::auto_ptr<IVolumeSlicer> layerSource;
+    boost::shared_ptr<IVolumeSlicer> layerSource;
     std::string sliceKeyId = instanceId + ":" + boost::lexical_cast<std::string>(frame);
     SmartLoader::CachedSlice* cachedSlice = NULL;
 
@@ -151,22 +142,23 @@
     }
     else
     {
-      layerSource.reset(new DicomSeriesVolumeSlicer(IObserver::GetBroker(), orthancApiClient_));
+      layerSource.reset(new DicomSeriesVolumeSlicer);
+      dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->Connect(orthancApiClient_);
       dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->SetImageQuality(imageQuality_);
-      layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, IVolumeSlicer::GeometryReadyMessage>(*this, &SmartLoader::OnLayerGeometryReady));
-      layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, DicomSeriesVolumeSlicer::FrameReadyMessage>(*this, &SmartLoader::OnFrameReady));
-      layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, IVolumeSlicer::LayerReadyMessage>(*this, &SmartLoader::OnLayerReady));
+      Register<IVolumeSlicer::GeometryReadyMessage>(*layerSource, &SmartLoader::OnLayerGeometryReady);
+      Register<DicomSeriesVolumeSlicer::FrameReadyMessage>(*layerSource, &SmartLoader::OnFrameReady);
+      Register<IVolumeSlicer::LayerReadyMessage>(*layerSource, &SmartLoader::OnLayerReady);
       dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->LoadFrame(instanceId, frame);
     }
 
     // make sure that the widget registers the events before we trigger them
     if (sliceViewer.GetLayerCount() == layerIndex)
     {
-      sliceViewer.AddLayer(layerSource.release());
+      sliceViewer.AddLayer(layerSource);
     }
     else if (sliceViewer.GetLayerCount() > layerIndex)
     {
-      sliceViewer.ReplaceLayer(layerIndex, layerSource.release());
+      sliceViewer.ReplaceLayer(layerIndex, layerSource);
     }
     else
     {
@@ -190,7 +182,7 @@
 
 
     // create the slice in the cache with "empty" data
-    boost::shared_ptr<CachedSlice> cachedSlice(new CachedSlice(IObserver::GetBroker()));
+    boost::shared_ptr<CachedSlice> cachedSlice(new CachedSlice);
     cachedSlice->slice_.reset(new Slice(instanceId, frame));
     cachedSlice->status_ = CachedSliceStatus_ScheduledToLoad;
     std::string sliceKeyId = instanceId + ":" + boost::lexical_cast<std::string>(frame);
@@ -199,12 +191,12 @@
 
     cachedSlices_[sliceKeyId] = boost::shared_ptr<CachedSlice>(cachedSlice);
 
-    std::auto_ptr<IVolumeSlicer> layerSource(new DicomSeriesVolumeSlicer(IObserver::GetBroker(), orthancApiClient_));
-
+    std::auto_ptr<IVolumeSlicer> layerSource(new DicomSeriesVolumeSlicer);
+    dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->Connect(orthancApiClient_);
     dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->SetImageQuality(imageQuality_);
-    layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, IVolumeSlicer::GeometryReadyMessage>(*this, &SmartLoader::OnLayerGeometryReady));
-    layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, DicomSeriesVolumeSlicer::FrameReadyMessage>(*this, &SmartLoader::OnFrameReady));
-    layerSource->RegisterObserverCallback(new OrthancStone::Callable<SmartLoader, IVolumeSlicer::LayerReadyMessage>(*this, &SmartLoader::OnLayerReady));
+    Register<IVolumeSlicer::GeometryReadyMessage>(*layerSource, &SmartLoader::OnLayerGeometryReady);
+    Register<DicomSeriesVolumeSlicer::FrameReadyMessage>(*layerSource, &SmartLoader::OnFrameReady);
+    Register<IVolumeSlicer::LayerReadyMessage>(*layerSource, &SmartLoader::OnLayerReady);
     dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->LoadFrame(instanceId, frame);
 
     // keep a ref to the VolumeSlicer until the slice is fully loaded and saved to cache
@@ -235,7 +227,7 @@
 
     LOG(WARNING) << "Geometry ready: " << sliceKeyId;
 
-    boost::shared_ptr<CachedSlice> cachedSlice(new CachedSlice(IObserver::GetBroker()));
+    boost::shared_ptr<CachedSlice> cachedSlice(new CachedSlice);
     cachedSlice->slice_.reset(slice.Clone());
     cachedSlice->effectiveQuality_ = source.GetImageQuality();
     cachedSlice->status_ = CachedSliceStatus_GeometryLoaded;
@@ -256,7 +248,7 @@
 
     LOG(WARNING) << "Image ready: " << sliceKeyId;
 
-    boost::shared_ptr<CachedSlice> cachedSlice(new CachedSlice(IObserver::GetBroker()));
+    boost::shared_ptr<CachedSlice> cachedSlice(new CachedSlice);
     cachedSlice->image_.reset(Orthanc::Image::Clone(message.GetFrame()));
     cachedSlice->effectiveQuality_ = message.GetImageQuality();
     cachedSlice->slice_.reset(message.GetSlice().Clone());
--- a/Framework/Deprecated/SmartLoader.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Deprecated/SmartLoader.h	Wed Oct 23 11:04:47 2019 +0200
@@ -30,7 +30,7 @@
 {
   class SliceViewerWidget;
 
-  class SmartLoader : public OrthancStone::IObservable, public OrthancStone::IObserver
+  class SmartLoader : public OrthancStone::IObservable, public OrthancStone::ObserverBase<SmartLoader>
   {
     class CachedSlice;
 
@@ -42,10 +42,10 @@
     PreloadingInstances preloadingInstances_;
 
     SliceImageQuality     imageQuality_;
-    OrthancApiClient&     orthancApiClient_;
+    boost::shared_ptr<OrthancApiClient>  orthancApiClient_;
 
   public:
-    SmartLoader(OrthancStone::MessageBroker& broker, OrthancApiClient& orthancApiClient);  // TODO: add maxPreloadStorageSizeInBytes
+    SmartLoader(boost::shared_ptr<OrthancApiClient> orthancApiClient);  // TODO: add maxPreloadStorageSizeInBytes
 
 //    void PreloadStudy(const std::string studyId);
 //    void PreloadSeries(const std::string seriesId);
--- a/Framework/Deprecated/Toolbox/BaseWebService.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Deprecated/Toolbox/BaseWebService.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -97,9 +97,9 @@
       GetAsyncInternal(uri, headers,
                        new BaseWebService::BaseWebServicePayload(successCallback, failureCallback, payload), // ownership is transfered
                        new OrthancStone::Callable<BaseWebService, IWebService::HttpRequestSuccessMessage>
-                       (*this, &BaseWebService::CacheAndNotifyHttpSuccess),
+                       (GetSharedObserver(), &BaseWebService::CacheAndNotifyHttpSuccess),
                        new OrthancStone::Callable<BaseWebService, IWebService::HttpRequestErrorMessage>
-                       (*this, &BaseWebService::NotifyHttpError),
+                       (GetSharedObserver(), &BaseWebService::NotifyHttpError),
                        timeoutInSeconds);
     }
     else
--- a/Framework/Deprecated/Toolbox/BaseWebService.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Deprecated/Toolbox/BaseWebService.h	Wed Oct 23 11:04:47 2019 +0200
@@ -22,6 +22,7 @@
 #pragma once
 
 #include "IWebService.h"
+#include "../../Messages/ObserverBase.h"
 
 #include <string>
 #include <map>
@@ -31,7 +32,7 @@
 {
   // This is an intermediate of IWebService that implements some caching on
   // the HTTP GET requests
-  class BaseWebService : public IWebService, public OrthancStone::IObserver
+  class BaseWebService : public IWebService, public OrthancStone::ObserverBase<BaseWebService>
   {
   public:
     class CachedHttpRequestSuccessMessage
@@ -90,10 +91,7 @@
     std::deque<std::string> orderedCacheKeys_;
 
   public:
-
-    BaseWebService(OrthancStone::MessageBroker& broker) :
-      IWebService(broker),
-      IObserver(broker),
+    BaseWebService() :
       cacheEnabled_(false),
       cacheCurrentSize_(0),
       cacheMaxSize_(100*1024*1024)
--- a/Framework/Deprecated/Toolbox/IDelayedCallExecutor.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Deprecated/Toolbox/IDelayedCallExecutor.h	Wed Oct 23 11:04:47 2019 +0200
@@ -35,22 +35,12 @@
   // The IDelayedCall executes a callback after a delay (equivalent to timeout() function in javascript).
   class IDelayedCallExecutor : public boost::noncopyable
   {
-  protected:
-    OrthancStone::MessageBroker& broker_;
-    
   public:
     ORTHANC_STONE_DEFINE_EMPTY_MESSAGE(__FILE__, __LINE__, TimeoutMessage);
 
-    IDelayedCallExecutor(OrthancStone::MessageBroker& broker) :
-      broker_(broker)
-    {
-    }
-
-    
     virtual ~IDelayedCallExecutor()
     {
     }
-
     
     virtual void Schedule(OrthancStone::MessageHandler<IDelayedCallExecutor::TimeoutMessage>* callback,
                           unsigned int timeoutInMs = 1000) = 0;
--- a/Framework/Deprecated/Toolbox/IWebService.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Deprecated/Toolbox/IWebService.h	Wed Oct 23 11:04:47 2019 +0200
@@ -40,9 +40,6 @@
   // and you'll be notified when the response/error is ready.
   class IWebService : public boost::noncopyable
   {
-  protected:
-    OrthancStone::MessageBroker& broker_;
-    
   public:
     typedef std::map<std::string, std::string> HttpHeaders;
 
@@ -138,12 +135,6 @@
     };
 
 
-    IWebService(OrthancStone::MessageBroker& broker) :
-      broker_(broker)
-    {
-    }
-
-    
     virtual ~IWebService()
     {
     }
--- a/Framework/Deprecated/Toolbox/OrthancApiClient.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Deprecated/Toolbox/OrthancApiClient.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -73,7 +73,6 @@
     std::auto_ptr< OrthancStone::MessageHandler<BinaryResponseReadyMessage> >            binaryHandler_;
     std::auto_ptr< OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage> >  failureHandler_;
     std::auto_ptr< Orthanc::IDynamicObject >                               userPayload_;
-    OrthancStone::MessageBroker&                                                         broker_;
     void NotifyConversionError(const IWebService::HttpRequestSuccessMessage& message) const
     {
       if (failureHandler_.get() != NULL)
@@ -84,14 +83,12 @@
     }
     
   public:
-    WebServicePayload(OrthancStone::MessageBroker& broker,
-                      OrthancStone::MessageHandler<EmptyResponseReadyMessage>* handler,
+    WebServicePayload(OrthancStone::MessageHandler<EmptyResponseReadyMessage>* handler,
                       OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureHandler,
                       Orthanc::IDynamicObject* userPayload) :
       emptyHandler_(handler),
       failureHandler_(failureHandler),
-      userPayload_(userPayload),
-      broker_(broker)
+      userPayload_(userPayload)
 
     {
       if (handler == NULL)
@@ -100,14 +97,12 @@
       }
     }
 
-    WebServicePayload(OrthancStone::MessageBroker& broker,
-                      OrthancStone::MessageHandler<BinaryResponseReadyMessage>* handler,
+    WebServicePayload(OrthancStone::MessageHandler<BinaryResponseReadyMessage>* handler,
                       OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureHandler,
                       Orthanc::IDynamicObject* userPayload) :
       binaryHandler_(handler),
       failureHandler_(failureHandler),
-      userPayload_(userPayload),
-      broker_(broker)
+      userPayload_(userPayload)
     {
       if (handler == NULL)
       {
@@ -115,14 +110,12 @@
       }
     }
 
-    WebServicePayload(OrthancStone::MessageBroker& broker,
-                      OrthancStone::MessageHandler<JsonResponseReadyMessage>* handler,
+    WebServicePayload(OrthancStone::MessageHandler<JsonResponseReadyMessage>* handler,
                       OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureHandler,
                       Orthanc::IDynamicObject* userPayload) :
       jsonHandler_(handler),
       failureHandler_(failureHandler),
-      userPayload_(userPayload),
-      broker_(broker)
+      userPayload_(userPayload)
     {
       if (handler == NULL)
       {
@@ -134,35 +127,26 @@
     {
       if (emptyHandler_.get() != NULL)
       {
-        if (broker_.IsActive(*(emptyHandler_->GetObserver())))
-        {
-          emptyHandler_->Apply(OrthancApiClient::EmptyResponseReadyMessage
-                               (message.GetUri(), userPayload_.get()));
-        }
+        emptyHandler_->Apply(OrthancApiClient::EmptyResponseReadyMessage
+                             (message.GetUri(), userPayload_.get()));
       }
       else if (binaryHandler_.get() != NULL)
       {
-        if (broker_.IsActive(*(binaryHandler_->GetObserver())))
-        {
-          binaryHandler_->Apply(OrthancApiClient::BinaryResponseReadyMessage
-                                (message.GetUri(), message.GetAnswer(),
-                                 message.GetAnswerSize(), userPayload_.get()));
-        }
+        binaryHandler_->Apply(OrthancApiClient::BinaryResponseReadyMessage
+                              (message.GetUri(), message.GetAnswer(),
+                               message.GetAnswerSize(), userPayload_.get()));
       }
       else if (jsonHandler_.get() != NULL)
       {
-        if (broker_.IsActive(*(jsonHandler_->GetObserver())))
+        Json::Value response;
+        if (MessagingToolbox::ParseJson(response, message.GetAnswer(), message.GetAnswerSize()))
         {
-          Json::Value response;
-          if (MessagingToolbox::ParseJson(response, message.GetAnswer(), message.GetAnswerSize()))
-          {
-            jsonHandler_->Apply(OrthancApiClient::JsonResponseReadyMessage
-                                (message.GetUri(), response, userPayload_.get()));
-          }
-          else
-          {
-            NotifyConversionError(message);
-          }
+          jsonHandler_->Apply(OrthancApiClient::JsonResponseReadyMessage
+                              (message.GetUri(), response, userPayload_.get()));
+        }
+        else
+        {
+          NotifyConversionError(message);
         }
       }
       else
@@ -182,11 +166,8 @@
   };
 
 
-  OrthancApiClient::OrthancApiClient(OrthancStone::MessageBroker& broker,
-                                     IWebService& web,
+  OrthancApiClient::OrthancApiClient(IWebService& web,
                                      const std::string& baseUrl) :
-    IObservable(broker),
-    IObserver(broker),
     web_(web),
     baseUrl_(baseUrl)
   {
@@ -202,11 +183,11 @@
     IWebService::HttpHeaders emptyHeaders;
     web_.GetAsync(baseUrl_ + uri,
                   emptyHeaders,
-                  new WebServicePayload(IObservable::GetBroker(), successCallback, failureCallback, payload),
+                  new WebServicePayload(successCallback, failureCallback, payload),
                   new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
-                  (*this, &OrthancApiClient::NotifyHttpSuccess),
+                  (GetSharedObserver(), &OrthancApiClient::NotifyHttpSuccess),
                   new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
-                  (*this, &OrthancApiClient::NotifyHttpError));
+                  (GetSharedObserver(), &OrthancApiClient::NotifyHttpError));
   }
 
 
@@ -232,11 +213,11 @@
     // printf("GET [%s] [%s]\n", baseUrl_.c_str(), uri.c_str());
 
     web_.GetAsync(baseUrl_ + uri, headers,
-                  new WebServicePayload(IObservable::GetBroker(), successCallback, failureCallback, payload),
+                  new WebServicePayload(successCallback, failureCallback, payload),
                   new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
-                  (*this, &OrthancApiClient::NotifyHttpSuccess),
+                  (GetSharedObserver(), &OrthancApiClient::NotifyHttpSuccess),
                   new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
-                  (*this, &OrthancApiClient::NotifyHttpError));
+                  (GetSharedObserver(), &OrthancApiClient::NotifyHttpError));
   }
 
   
@@ -248,11 +229,11 @@
       Orthanc::IDynamicObject* payload)
   {
     web_.PostAsync(baseUrl_ + uri, IWebService::HttpHeaders(), body,
-                   new WebServicePayload(IObservable::GetBroker(), successCallback, failureCallback, payload),
+                   new WebServicePayload(successCallback, failureCallback, payload),
                    new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
-                   (*this, &OrthancApiClient::NotifyHttpSuccess),
+                   (GetSharedObserver(), &OrthancApiClient::NotifyHttpSuccess),
                    new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
-                   (*this, &OrthancApiClient::NotifyHttpError));
+                   (GetSharedObserver(), &OrthancApiClient::NotifyHttpError));
 
   }
 
@@ -271,11 +252,11 @@
       Orthanc::IDynamicObject* payload   /* takes ownership */)
   {
     web_.PostAsync(baseUrl_ + uri, IWebService::HttpHeaders(), body,
-                   new WebServicePayload(IObservable::GetBroker(), successCallback, failureCallback, payload),
+                   new WebServicePayload(successCallback, failureCallback, payload),
                    new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
-                   (*this, &OrthancApiClient::NotifyHttpSuccess),
+                   (GetSharedObserver(), &OrthancApiClient::NotifyHttpSuccess),
                    new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
-                   (*this, &OrthancApiClient::NotifyHttpError));
+                   (GetSharedObserver(), &OrthancApiClient::NotifyHttpError));
   }
 
   void OrthancApiClient::PostJsonAsyncExpectJson(
@@ -318,11 +299,11 @@
       Orthanc::IDynamicObject* payload)
   {
     web_.DeleteAsync(baseUrl_ + uri, IWebService::HttpHeaders(),
-                     new WebServicePayload(IObservable::GetBroker(), successCallback, failureCallback, payload),
+                     new WebServicePayload(successCallback, failureCallback, payload),
                      new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
-                     (*this, &OrthancApiClient::NotifyHttpSuccess),
+                     (GetSharedObserver(), &OrthancApiClient::NotifyHttpSuccess),
                      new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
-                     (*this, &OrthancApiClient::NotifyHttpError));
+                     (GetSharedObserver(), &OrthancApiClient::NotifyHttpError));
   }
 
 
--- a/Framework/Deprecated/Toolbox/OrthancApiClient.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Deprecated/Toolbox/OrthancApiClient.h	Wed Oct 23 11:04:47 2019 +0200
@@ -25,13 +25,13 @@
 #include <json/json.h>
 
 #include "IWebService.h"
-#include "../../Messages/IObservable.h"
+#include "../../Messages/ObserverBase.h"
 
 namespace Deprecated
 {
   class OrthancApiClient :
       public OrthancStone::IObservable,
-      public OrthancStone::IObserver
+      public OrthancStone::ObserverBase<OrthancApiClient>
   {
   public:
     class JsonResponseReadyMessage : public OrthancStone::IMessage
@@ -157,8 +157,7 @@
     std::string   baseUrl_;
 
   public:
-    OrthancApiClient(OrthancStone::MessageBroker& broker,
-                     IWebService& web,
+    OrthancApiClient(IWebService& web,
                      const std::string& baseUrl);
     
     virtual ~OrthancApiClient()
--- a/Framework/Deprecated/Toolbox/OrthancSlicesLoader.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Deprecated/Toolbox/OrthancSlicesLoader.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -639,10 +639,7 @@
   }
   
   
-  OrthancSlicesLoader::OrthancSlicesLoader(OrthancStone::MessageBroker& broker,
-                                           OrthancApiClient& orthanc) :
-    OrthancStone::IObservable(broker),
-    OrthancStone::IObserver(broker),
+  OrthancSlicesLoader::OrthancSlicesLoader(boost::shared_ptr<OrthancApiClient> orthanc) :
     orthanc_(orthanc),
     state_(State_Initialization)
   {
@@ -658,10 +655,10 @@
     else
     {
       state_ = State_LoadingGeometry;
-      orthanc_.GetJsonAsync("/series/" + seriesId + "/instances-tags",
-                            new OrthancStone::Callable<OrthancSlicesLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &OrthancSlicesLoader::ParseSeriesGeometry),
-                            new OrthancStone::Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(*this, &OrthancSlicesLoader::OnGeometryError),
-                            NULL);
+      orthanc_->GetJsonAsync("/series/" + seriesId + "/instances-tags",
+                             new OrthancStone::Callable<OrthancSlicesLoader, OrthancApiClient::JsonResponseReadyMessage>(GetSharedObserver(), &OrthancSlicesLoader::ParseSeriesGeometry),
+                             new OrthancStone::Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(GetSharedObserver(), &OrthancSlicesLoader::OnGeometryError),
+                             NULL);
     }
   }
   
@@ -677,10 +674,10 @@
       
       // Tag "3004-000c" is "Grid Frame Offset Vector", which is
       // mandatory to read RT DOSE, but is too long to be returned by default
-      orthanc_.GetJsonAsync("/instances/" + instanceId + "/tags?ignore-length=3004-000c",
-                            new OrthancStone::Callable<OrthancSlicesLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &OrthancSlicesLoader::ParseInstanceGeometry),
-                            new OrthancStone::Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(*this, &OrthancSlicesLoader::OnGeometryError),
-                            Operation::DownloadInstanceGeometry(instanceId));
+      orthanc_->GetJsonAsync("/instances/" + instanceId + "/tags?ignore-length=3004-000c",
+                             new OrthancStone::Callable<OrthancSlicesLoader, OrthancApiClient::JsonResponseReadyMessage>(GetSharedObserver(), &OrthancSlicesLoader::ParseInstanceGeometry),
+                             new OrthancStone::Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(GetSharedObserver(), &OrthancSlicesLoader::OnGeometryError),
+                             Operation::DownloadInstanceGeometry(instanceId));
     }
   }
   
@@ -696,10 +693,10 @@
     {
       state_ = State_LoadingGeometry;
 
-      orthanc_.GetJsonAsync("/instances/" + instanceId + "/tags",
-                            new OrthancStone::Callable<OrthancSlicesLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &OrthancSlicesLoader::ParseFrameGeometry),
-                            new OrthancStone::Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(*this, &OrthancSlicesLoader::OnGeometryError),
-                            Operation::DownloadFrameGeometry(instanceId, frame));
+      orthanc_->GetJsonAsync("/instances/" + instanceId + "/tags",
+                             new OrthancStone::Callable<OrthancSlicesLoader, OrthancApiClient::JsonResponseReadyMessage>(GetSharedObserver(), &OrthancSlicesLoader::ParseFrameGeometry),
+                             new OrthancStone::Callable<OrthancSlicesLoader, IWebService::HttpRequestErrorMessage>(GetSharedObserver(), &OrthancSlicesLoader::OnGeometryError),
+                             Operation::DownloadFrameGeometry(instanceId, frame));
     }
   }
   
@@ -770,23 +767,23 @@
         throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
     }
     
-    orthanc_.GetBinaryAsync(uri, "image/png",
-      new OrthancStone::Callable<OrthancSlicesLoader, 
-        OrthancApiClient::BinaryResponseReadyMessage>
-          (*this, &OrthancSlicesLoader::ParseSliceImagePng),
-      new OrthancStone::Callable<OrthancSlicesLoader, 
-        IWebService::HttpRequestErrorMessage>
-          (*this, &OrthancSlicesLoader::OnSliceImageError),
-      Operation::DownloadSliceImage(
-        static_cast<unsigned int>(index), slice, SliceImageQuality_FullPng));
-}
+    orthanc_->GetBinaryAsync(uri, "image/png",
+                             new OrthancStone::Callable<OrthancSlicesLoader, 
+                             OrthancApiClient::BinaryResponseReadyMessage>
+                             (GetSharedObserver(), &OrthancSlicesLoader::ParseSliceImagePng),
+                             new OrthancStone::Callable<OrthancSlicesLoader, 
+                             IWebService::HttpRequestErrorMessage>
+                             (GetSharedObserver(), &OrthancSlicesLoader::OnSliceImageError),
+                             Operation::DownloadSliceImage(
+                               static_cast<unsigned int>(index), slice, SliceImageQuality_FullPng));
+  }
   
   void OrthancSlicesLoader::ScheduleSliceImagePam(const Slice& slice,
                                                   size_t index)
   {
     std::string uri = 
       ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" +
-      boost::lexical_cast<std::string>(slice.GetFrame()));
+       boost::lexical_cast<std::string>(slice.GetFrame()));
 
     switch (slice.GetConverter().GetExpectedPixelFormat())
     {
@@ -806,15 +803,15 @@
         throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
     }
 
-    orthanc_.GetBinaryAsync(uri, "image/x-portable-arbitrarymap",
-      new OrthancStone::Callable<OrthancSlicesLoader, 
-        OrthancApiClient::BinaryResponseReadyMessage>
-          (*this, &OrthancSlicesLoader::ParseSliceImagePam),
-      new OrthancStone::Callable<OrthancSlicesLoader, 
-        IWebService::HttpRequestErrorMessage>
-          (*this, &OrthancSlicesLoader::OnSliceImageError),
-      Operation::DownloadSliceImage(static_cast<unsigned int>(index), 
-                                    slice, SliceImageQuality_FullPam));
+    orthanc_->GetBinaryAsync(uri, "image/x-portable-arbitrarymap",
+                             new OrthancStone::Callable<OrthancSlicesLoader, 
+                             OrthancApiClient::BinaryResponseReadyMessage>
+                             (GetSharedObserver(), &OrthancSlicesLoader::ParseSliceImagePam),
+                             new OrthancStone::Callable<OrthancSlicesLoader, 
+                             IWebService::HttpRequestErrorMessage>
+                             (GetSharedObserver(), &OrthancSlicesLoader::OnSliceImageError),
+                             Operation::DownloadSliceImage(static_cast<unsigned int>(index), 
+                                                           slice, SliceImageQuality_FullPam));
   }
 
 
@@ -849,15 +846,15 @@
                        "-" + slice.GetOrthancInstanceId() + "_" +
                        boost::lexical_cast<std::string>(slice.GetFrame()));
 
-    orthanc_.GetJsonAsync(uri,
-      new OrthancStone::Callable<OrthancSlicesLoader, 
-        OrthancApiClient::JsonResponseReadyMessage>
-          (*this, &OrthancSlicesLoader::ParseSliceImageJpeg),
-      new OrthancStone::Callable<OrthancSlicesLoader, 
-        IWebService::HttpRequestErrorMessage>
-          (*this, &OrthancSlicesLoader::OnSliceImageError),
-        Operation::DownloadSliceImage(
-          static_cast<unsigned int>(index), slice, quality));
+    orthanc_->GetJsonAsync(uri,
+                           new OrthancStone::Callable<OrthancSlicesLoader, 
+                           OrthancApiClient::JsonResponseReadyMessage>
+                           (GetSharedObserver(), &OrthancSlicesLoader::ParseSliceImageJpeg),
+                           new OrthancStone::Callable<OrthancSlicesLoader, 
+                           IWebService::HttpRequestErrorMessage>
+                           (GetSharedObserver(), &OrthancSlicesLoader::OnSliceImageError),
+                           Operation::DownloadSliceImage(
+                             static_cast<unsigned int>(index), slice, quality));
   }
   
   
@@ -890,15 +887,15 @@
     {
       std::string uri = ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" +
                          boost::lexical_cast<std::string>(slice.GetFrame()) + "/raw.gz");
-      orthanc_.GetBinaryAsync(uri, IWebService::HttpHeaders(),
-        new OrthancStone::Callable<OrthancSlicesLoader, 
-          OrthancApiClient::BinaryResponseReadyMessage>
-            (*this, &OrthancSlicesLoader::ParseSliceRawImage),
-        new OrthancStone::Callable<OrthancSlicesLoader,
-          IWebService::HttpRequestErrorMessage>
-            (*this, &OrthancSlicesLoader::OnSliceImageError),
-        Operation::DownloadSliceRawImage(
-          static_cast<unsigned int>(index), slice));
+      orthanc_->GetBinaryAsync(uri, IWebService::HttpHeaders(),
+                               new OrthancStone::Callable<OrthancSlicesLoader, 
+                               OrthancApiClient::BinaryResponseReadyMessage>
+                               (GetSharedObserver(), &OrthancSlicesLoader::ParseSliceRawImage),
+                               new OrthancStone::Callable<OrthancSlicesLoader,
+                               IWebService::HttpRequestErrorMessage>
+                               (GetSharedObserver(), &OrthancSlicesLoader::OnSliceImageError),
+                               Operation::DownloadSliceRawImage(
+                                 static_cast<unsigned int>(index), slice));
     }
   }
 }
--- a/Framework/Deprecated/Toolbox/OrthancSlicesLoader.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Deprecated/Toolbox/OrthancSlicesLoader.h	Wed Oct 23 11:04:47 2019 +0200
@@ -22,6 +22,7 @@
 #pragma once
 
 #include "../../Messages/IObservable.h"
+#include "../../Messages/ObserverBase.h"
 #include "../../StoneEnumerations.h"
 #include "../../Toolbox/SlicesSorter.h"
 #include "IWebService.h"
@@ -33,7 +34,9 @@
 
 namespace Deprecated
 {
-  class OrthancSlicesLoader : public OrthancStone::IObservable, public OrthancStone::IObserver
+  class OrthancSlicesLoader :
+    public OrthancStone::IObservable,
+    public OrthancStone::ObserverBase<OrthancSlicesLoader>
   {
   public:
     ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, SliceGeometryReadyMessage, OrthancSlicesLoader);
@@ -143,7 +146,7 @@
 
     class Operation;
 
-    OrthancApiClient&  orthanc_;
+    boost::shared_ptr<OrthancApiClient>  orthanc_;
     State         state_;
     OrthancStone::SlicesSorter  slices_;
 
@@ -183,9 +186,8 @@
     void SortAndFinalizeSlices();
     
   public:
-    OrthancSlicesLoader(OrthancStone::MessageBroker& broker,
-                        //ISliceLoaderObserver& callback,
-                        OrthancApiClient& orthancApi);
+    OrthancSlicesLoader(//ISliceLoaderObserver& callback,
+      boost::shared_ptr<OrthancApiClient> orthancApi);
 
     void ScheduleLoadSeries(const std::string& seriesId);
 
--- a/Framework/Deprecated/Viewport/IViewport.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Deprecated/Viewport/IViewport.h	Wed Oct 23 11:04:47 2019 +0200
@@ -37,15 +37,6 @@
   public:
     ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ViewportChangedMessage, IViewport);
 
-    IViewport(OrthancStone::MessageBroker& broker) :
-      IObservable(broker)
-    {
-    }
-    
-    virtual ~IViewport()
-    {
-    }
-
     virtual void FitContent() = 0;
 
     virtual void SetStatusBar(IStatusBar& statusBar) = 0;
--- a/Framework/Deprecated/Viewport/WidgetViewport.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Deprecated/Viewport/WidgetViewport.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -26,8 +26,7 @@
 
 namespace Deprecated
 {
-  WidgetViewport::WidgetViewport(OrthancStone::MessageBroker& broker) :
-    IViewport(broker),
+  WidgetViewport::WidgetViewport() :
     statusBar_(NULL),
     isMouseOver_(false),
     lastMouseX_(0),
@@ -57,7 +56,7 @@
   }
 
 
-  IWidget& WidgetViewport::SetCentralWidget(IWidget* widget)
+  void WidgetViewport::SetCentralWidget(boost::shared_ptr<IWidget> widget)
   {
     if (widget == NULL)
     {
@@ -66,7 +65,7 @@
 
     mouseTracker_.reset(NULL);
 
-    centralWidget_.reset(widget);
+    centralWidget_ = widget;
     centralWidget_->SetViewport(*this);
 
     if (statusBar_ != NULL)
@@ -75,8 +74,6 @@
     }
 
     NotifyBackgroundChanged();
-
-    return *widget;
   }
 
 
--- a/Framework/Deprecated/Viewport/WidgetViewport.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Deprecated/Viewport/WidgetViewport.h	Wed Oct 23 11:04:47 2019 +0200
@@ -31,7 +31,7 @@
   class WidgetViewport : public IViewport
   {
   private:
-    std::auto_ptr<IWidget>        centralWidget_;
+    boost::shared_ptr<IWidget>    centralWidget_;
     IStatusBar*                   statusBar_;
     std::auto_ptr<IMouseTracker>  mouseTracker_;
     bool                          isMouseOver_;
@@ -41,13 +41,13 @@
     bool                          backgroundChanged_;
 
   public:
-    WidgetViewport(OrthancStone::MessageBroker& broker);
+    WidgetViewport();
 
     virtual void FitContent();
 
     virtual void SetStatusBar(IStatusBar& statusBar);
 
-    IWidget& SetCentralWidget(IWidget* widget);  // Takes ownership
+    void SetCentralWidget(boost::shared_ptr<IWidget> widget);
 
     virtual void NotifyBackgroundChanged();
 
--- a/Framework/Deprecated/Volumes/ISlicedVolume.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Deprecated/Volumes/ISlicedVolume.h	Wed Oct 23 11:04:47 2019 +0200
@@ -65,11 +65,6 @@
     };
 
 
-    ISlicedVolume(OrthancStone::MessageBroker& broker) :
-      IObservable(broker)
-    {
-    }
-    
     virtual size_t GetSliceCount() const = 0;
 
     virtual const Slice& GetSlice(size_t slice) const = 0;
--- a/Framework/Deprecated/Volumes/IVolumeLoader.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Deprecated/Volumes/IVolumeLoader.h	Wed Oct 23 11:04:47 2019 +0200
@@ -31,10 +31,5 @@
     ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryReadyMessage, IVolumeLoader);
     ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryErrorMessage, IVolumeLoader);
     ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ContentChangedMessage, IVolumeLoader);
-
-    IVolumeLoader(OrthancStone::MessageBroker& broker) :
-      IObservable(broker)
-    {
-    }
   };
 }
--- a/Framework/Deprecated/Volumes/StructureSetLoader.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Deprecated/Volumes/StructureSetLoader.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -27,10 +27,7 @@
 
 namespace Deprecated
 {
-  StructureSetLoader::StructureSetLoader(OrthancStone::MessageBroker& broker,
-                                         OrthancApiClient& orthanc) :
-    IVolumeLoader(broker),
-    IObserver(broker),
+  StructureSetLoader::StructureSetLoader(OrthancApiClient& orthanc) :
     orthanc_(orthanc)
   {
   }
@@ -60,7 +57,7 @@
          it != instances.end(); ++it)
     {
       orthanc_.PostBinaryAsyncExpectJson("/tools/lookup", *it,
-                                         new OrthancStone::Callable<StructureSetLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &StructureSetLoader::OnLookupCompleted));
+                                         new OrthancStone::Callable<StructureSetLoader, OrthancApiClient::JsonResponseReadyMessage>(GetSharedObserver(), &StructureSetLoader::OnLookupCompleted));
     }
 
     BroadcastMessage(GeometryReadyMessage(*this));
@@ -84,7 +81,7 @@
 
     const std::string& instance = lookup[0]["ID"].asString();
     orthanc_.GetJsonAsync("/instances/" + instance + "/tags",
-                          new OrthancStone::Callable<StructureSetLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &StructureSetLoader::OnReferencedSliceLoaded));
+                          new OrthancStone::Callable<StructureSetLoader, OrthancApiClient::JsonResponseReadyMessage>(GetSharedObserver(), &StructureSetLoader::OnReferencedSliceLoaded));
   }
 
   
@@ -97,7 +94,7 @@
     else
     {
       orthanc_.GetJsonAsync("/instances/" + instance + "/tags?ignore-length=3006-0050",
-                            new OrthancStone::Callable<StructureSetLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &StructureSetLoader::OnStructureSetLoaded));
+                            new OrthancStone::Callable<StructureSetLoader, OrthancApiClient::JsonResponseReadyMessage>(GetSharedObserver(), &StructureSetLoader::OnStructureSetLoaded));
     }
   }
 
--- a/Framework/Deprecated/Volumes/StructureSetLoader.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Deprecated/Volumes/StructureSetLoader.h	Wed Oct 23 11:04:47 2019 +0200
@@ -21,6 +21,7 @@
 
 #pragma once
 
+#include "../../Messages/ObserverBase.h"
 #include "../../Toolbox/DicomStructureSet.h"
 #include "../Toolbox/OrthancApiClient.h"
 #include "IVolumeLoader.h"
@@ -29,7 +30,7 @@
 {
   class StructureSetLoader :
     public IVolumeLoader,
-    public OrthancStone::IObserver
+    public OrthancStone::ObserverBase<StructureSetLoader>
   {
   private:
     OrthancApiClient&                 orthanc_;
@@ -42,8 +43,7 @@
     void OnLookupCompleted(const OrthancApiClient::JsonResponseReadyMessage& message);
 
   public:
-    StructureSetLoader(OrthancStone::MessageBroker& broker,
-                       OrthancApiClient& orthanc);
+    StructureSetLoader(OrthancApiClient& orthanc);
 
     void ScheduleLoadInstance(const std::string& instance);
 
--- a/Framework/Deprecated/Widgets/LayoutWidget.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Deprecated/Widgets/LayoutWidget.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -85,14 +85,14 @@
   class LayoutWidget::ChildWidget : public boost::noncopyable
   {
   private:
-    std::auto_ptr<IWidget>  widget_;
+    boost::shared_ptr<IWidget>  widget_;
     int                     left_;
     int                     top_;
     unsigned int            width_;
     unsigned int            height_;
 
   public:
-    ChildWidget(IWidget* widget) :
+    ChildWidget(boost::shared_ptr<IWidget> widget) :
       widget_(widget)
     {
       assert(widget != NULL);
@@ -354,7 +354,7 @@
   }
 
 
-  IWidget& LayoutWidget::AddWidget(IWidget* widget)  // Takes ownership
+  void LayoutWidget::AddWidget(boost::shared_ptr<IWidget> widget)  // Takes ownership
   {
     if (widget == NULL)
     {
@@ -375,8 +375,6 @@
     {
       hasAnimation_ = true;
     }
-
-    return *widget;
   }
 
 
--- a/Framework/Deprecated/Widgets/LayoutWidget.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Deprecated/Widgets/LayoutWidget.h	Wed Oct 23 11:04:47 2019 +0200
@@ -94,7 +94,7 @@
       return paddingInternal_;
     }
 
-    IWidget& AddWidget(IWidget* widget);  // Takes ownership
+    void AddWidget(boost::shared_ptr<IWidget> widget);
 
     virtual void SetStatusBar(IStatusBar& statusBar);
 
--- a/Framework/Deprecated/Widgets/SliceViewerWidget.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Deprecated/Widgets/SliceViewerWidget.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -250,7 +250,7 @@
     {
       index = found->second;
       assert(index < layers_.size() &&
-             layers_[index] == &layer);
+             layers_[index].get() == &layer);
       return true;
     }
   }
@@ -364,42 +364,27 @@
   }
 
   
-  SliceViewerWidget::SliceViewerWidget(OrthancStone::MessageBroker& broker, 
-                                       const std::string& name) :
+  SliceViewerWidget::SliceViewerWidget(const std::string& name) :
     WorldSceneWidget(name),
-    IObserver(broker),
-    IObservable(broker),
     started_(false)
   {
     SetBackgroundCleared(true);
   }
   
   
-  SliceViewerWidget::~SliceViewerWidget()
-  {
-    for (size_t i = 0; i < layers_.size(); i++)
-    {
-      delete layers_[i];
-    }
-  }
-  
   void SliceViewerWidget::ObserveLayer(IVolumeSlicer& layer)
   {
-    layer.RegisterObserverCallback(new OrthancStone::Callable<SliceViewerWidget, IVolumeSlicer::GeometryReadyMessage>
-                                   (*this, &SliceViewerWidget::OnGeometryReady));
-    // currently ignore errors layer->RegisterObserverCallback(new Callable<SliceViewerWidget, IVolumeSlicer::GeometryErrorMessage>(*this, &SliceViewerWidget::...));
-    layer.RegisterObserverCallback(new OrthancStone::Callable<SliceViewerWidget, IVolumeSlicer::SliceContentChangedMessage>
-                                   (*this, &SliceViewerWidget::OnSliceChanged));
-    layer.RegisterObserverCallback(new OrthancStone::Callable<SliceViewerWidget, IVolumeSlicer::ContentChangedMessage>
-                                   (*this, &SliceViewerWidget::OnContentChanged));
-    layer.RegisterObserverCallback(new OrthancStone::Callable<SliceViewerWidget, IVolumeSlicer::LayerReadyMessage>
-                                   (*this, &SliceViewerWidget::OnLayerReady));
-    layer.RegisterObserverCallback(new OrthancStone::Callable<SliceViewerWidget, IVolumeSlicer::LayerErrorMessage>
-                                   (*this, &SliceViewerWidget::OnLayerError));
+    // currently ignoring errors of type IVolumeSlicer::GeometryErrorMessage
+
+    Register<IVolumeSlicer::GeometryReadyMessage>(layer, &SliceViewerWidget::OnGeometryReady);
+    Register<IVolumeSlicer::SliceContentChangedMessage>(layer, &SliceViewerWidget::OnSliceChanged);
+    Register<IVolumeSlicer::ContentChangedMessage>(layer, &SliceViewerWidget::OnContentChanged);
+    Register<IVolumeSlicer::LayerReadyMessage>(layer, &SliceViewerWidget::OnLayerReady);
+    Register<IVolumeSlicer::LayerErrorMessage>(layer, &SliceViewerWidget::OnLayerError);
   }
 
 
-  size_t SliceViewerWidget::AddLayer(IVolumeSlicer* layer)  // Takes ownership
+  size_t SliceViewerWidget::AddLayer(boost::shared_ptr<IVolumeSlicer> layer)
   {
     if (layer == NULL)
     {
@@ -409,7 +394,7 @@
     size_t index = layers_.size();
     layers_.push_back(layer);
     styles_.push_back(RenderStyle());
-    layersIndex_[layer] = index;
+    layersIndex_[layer.get()] = index;
 
     ResetPendingScene();
 
@@ -421,7 +406,8 @@
   }
 
 
-  void SliceViewerWidget::ReplaceLayer(size_t index, IVolumeSlicer* layer)  // Takes ownership
+  void SliceViewerWidget::ReplaceLayer(size_t index,
+                                       boost::shared_ptr<IVolumeSlicer> layer)
   {
     if (layer == NULL)
     {
@@ -433,9 +419,8 @@
       throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
     }
 
-    delete layers_[index];
     layers_[index] = layer;
-    layersIndex_[layer] = index;
+    layersIndex_[layer.get()] = index;
 
     ResetPendingScene();
 
@@ -452,13 +437,13 @@
       throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
     }
 
-    IVolumeSlicer* previousLayer = layers_[index];
+    IVolumeSlicer* previousLayer = layers_[index].get();
     layersIndex_.erase(layersIndex_.find(previousLayer));
     layers_.erase(layers_.begin() + index);
     changedLayers_.erase(changedLayers_.begin() + index);
     styles_.erase(styles_.begin() + index);
 
-    delete layers_[index];
+    layers_[index].reset();
 
     currentScene_->DeleteLayer(index);
     ResetPendingScene();
--- a/Framework/Deprecated/Widgets/SliceViewerWidget.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Deprecated/Widgets/SliceViewerWidget.h	Wed Oct 23 11:04:47 2019 +0200
@@ -24,7 +24,7 @@
 #include "WorldSceneWidget.h"
 #include "../Layers/IVolumeSlicer.h"
 #include "../../Toolbox/Extent2D.h"
-#include "../../Messages/IObserver.h"
+#include "../../Messages/ObserverBase.h"
 
 #include <map>
 
@@ -32,7 +32,7 @@
 {
   class SliceViewerWidget :
     public WorldSceneWidget,
-    public OrthancStone::IObserver,
+    public OrthancStone::ObserverBase<SliceViewerWidget>,
     public OrthancStone::IObservable
   {
   public:
@@ -72,7 +72,7 @@
 
     bool                         started_;
     LayersIndex                  layersIndex_;
-    std::vector<IVolumeSlicer*>  layers_;
+    std::vector<boost::shared_ptr<IVolumeSlicer> >  layers_;
     std::vector<RenderStyle>     styles_;
     OrthancStone::CoordinateSystem3D           plane_;
     std::auto_ptr<Scene>         currentScene_;
@@ -100,8 +100,7 @@
     void ResetChangedLayers();
 
   public:
-    SliceViewerWidget(OrthancStone::MessageBroker& broker, 
-                      const std::string& name);
+    SliceViewerWidget(const std::string& name);
 
     virtual OrthancStone::Extent2D GetSceneExtent();
 
@@ -120,11 +119,13 @@
     void InvalidateLayer(size_t layer);
     
   public:
-    virtual ~SliceViewerWidget();
+    virtual ~SliceViewerWidget()
+    {
+    }
 
-    size_t AddLayer(IVolumeSlicer* layer);  // Takes ownership
+    size_t AddLayer(boost::shared_ptr<IVolumeSlicer> layer);
 
-    void ReplaceLayer(size_t layerIndex, IVolumeSlicer* layer); // Takes ownership
+    void ReplaceLayer(size_t layerIndex, boost::shared_ptr<IVolumeSlicer> layer); // Takes ownership
 
     void RemoveLayer(size_t layerIndex);
 
--- a/Framework/Loaders/DicomStructureSetLoader.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Loaders/DicomStructureSetLoader.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -347,7 +347,6 @@
   DicomStructureSetLoader::DicomStructureSetLoader(IOracle& oracle,
                                                    IObservable& oracleObservable) :
     LoaderStateMachine(oracle, oracleObservable),
-    IObservable(oracleObservable.GetBroker()),
     revision_(0),
     countProcessedInstances_(0),
     countReferencedInstances_(0),
--- a/Framework/Loaders/LoaderStateMachine.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Loaders/LoaderStateMachine.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -97,7 +97,8 @@
         ") < simultaneousDownloads_ (" << simultaneousDownloads_ << 
         ") --> will Schedule command addr " << std::hex << nextCommand << std::dec;
 
-      oracle_.Schedule(*this, nextCommand);
+      boost::shared_ptr<IObserver> observer(GetSharedObserver());
+      oracle_.Schedule(observer, nextCommand);
       pendingCommands_.pop_front();
 
       activeCommands_++;
@@ -136,7 +137,6 @@
   template <typename T>
   void LoaderStateMachine::HandleSuccessMessage(const T& message)
   {
-    LOG(TRACE) << "LoaderStateMachine(" << std::hex << this << std::dec << ")::HandleSuccessMessage(). Receiver fingerprint = " << GetFingerprint();
     if (activeCommands_ <= 0) {
       LOG(ERROR) << "LoaderStateMachine(" << std::hex << this << std::dec << ")::HandleSuccessMessage : activeCommands_ should be > 0 but is: " << activeCommands_;
     }
@@ -159,35 +159,22 @@
 
   LoaderStateMachine::LoaderStateMachine(IOracle& oracle,
                                          IObservable& oracleObservable) :
-    IObserver(oracleObservable.GetBroker()),
     oracle_(oracle),
-    oracleObservable_(oracleObservable),
     active_(false),
     simultaneousDownloads_(4),
     activeCommands_(0)
   {
     LOG(TRACE) << "LoaderStateMachine(" << std::hex << this << std::dec << ")::LoaderStateMachine()";
 
-    oracleObservable.RegisterObserverCallback(
-      new Callable<LoaderStateMachine, OrthancRestApiCommand::SuccessMessage>
-      (*this, &LoaderStateMachine::HandleSuccessMessage));
-
-    oracleObservable.RegisterObserverCallback(
-      new Callable<LoaderStateMachine, GetOrthancImageCommand::SuccessMessage>
-      (*this, &LoaderStateMachine::HandleSuccessMessage));
-
-    oracleObservable.RegisterObserverCallback(
-      new Callable<LoaderStateMachine, GetOrthancWebViewerJpegCommand::SuccessMessage>
-      (*this, &LoaderStateMachine::HandleSuccessMessage));
-
-    oracleObservable.RegisterObserverCallback(
-      new Callable<LoaderStateMachine, OracleCommandExceptionMessage>
-      (*this, &LoaderStateMachine::HandleExceptionMessage));
+    // TODO => Move this out of constructor
+    Register<OrthancRestApiCommand::SuccessMessage>(oracleObservable, &LoaderStateMachine::HandleSuccessMessage);
+    Register<GetOrthancImageCommand::SuccessMessage>(oracleObservable, &LoaderStateMachine::HandleSuccessMessage);
+    Register<GetOrthancWebViewerJpegCommand::SuccessMessage>(oracleObservable, &LoaderStateMachine::HandleSuccessMessage);
+    Register<OracleCommandExceptionMessage>(oracleObservable, &LoaderStateMachine::HandleExceptionMessage);
   }
 
   LoaderStateMachine::~LoaderStateMachine()
   {
-    oracleObservable_.Unregister(this);
     LOG(TRACE) << "LoaderStateMachine(" << std::hex << this << std::dec << ")::~LoaderStateMachine()";
     Clear();
   }
--- a/Framework/Loaders/LoaderStateMachine.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Loaders/LoaderStateMachine.h	Wed Oct 23 11:04:47 2019 +0200
@@ -22,7 +22,7 @@
 #pragma once
 
 #include "../Messages/IObservable.h"
-#include "../Messages/IObserver.h"
+#include "../Messages/ObserverBase.h"
 #include "../Oracle/GetOrthancImageCommand.h"
 #include "../Oracle/GetOrthancWebViewerJpegCommand.h"
 #include "../Oracle/IOracle.h"
@@ -41,7 +41,7 @@
      rest once slots become available. It is used, a.o., by the 
      OrtancMultiframeVolumeLoader class.
   */
-  class LoaderStateMachine : public IObserver
+  class LoaderStateMachine : public ObserverBase<LoaderStateMachine>
   {
   protected:
     class State : public Orthanc::IDynamicObject
@@ -95,7 +95,6 @@
     typedef std::list<IOracleCommand*>  PendingCommands;
 
     IOracle&         oracle_;
-    IObservable&     oracleObservable_;
     bool             active_;
     unsigned int     simultaneousDownloads_;
     PendingCommands  pendingCommands_;
--- a/Framework/Loaders/OrthancMultiframeVolumeLoader.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Loaders/OrthancMultiframeVolumeLoader.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -335,7 +335,6 @@
                                                                IOracle& oracle,
                                                                IObservable& oracleObservable) :
     LoaderStateMachine(oracle, oracleObservable),
-    IObservable(oracleObservable.GetBroker()),
     volume_(volume),
     pixelDataLoaded_(false)
   {
--- a/Framework/Loaders/OrthancSeriesVolumeProgressiveLoader.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Loaders/OrthancSeriesVolumeProgressiveLoader.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -292,7 +292,9 @@
       }
 
       command->SetPayload(new Orthanc::SingleValueObject<unsigned int>(sliceIndex));
-      oracle_.Schedule(*this, command.release());
+
+      boost::shared_ptr<IObserver> observer(GetSharedObserver());
+      oracle_.Schedule(observer, command.release());
     }
     else
     {
@@ -421,32 +423,26 @@
   OrthancSeriesVolumeProgressiveLoader::OrthancSeriesVolumeProgressiveLoader(const boost::shared_ptr<DicomVolumeImage>& volume,
                                                                              IOracle& oracle,
                                                                              IObservable& oracleObservable) :
-    IObserver(oracleObservable.GetBroker()),
-    IObservable(oracleObservable.GetBroker()),
     oracle_(oracle),
-    oracleObservable_(oracleObservable),
     active_(false),
     simultaneousDownloads_(4),
     volume_(volume),
     sorter_(new BasicFetchingItemsSorter::Factory),
     volumeImageReadyInHighQuality_(false)
   {
-    oracleObservable.RegisterObserverCallback(
-      new Callable<OrthancSeriesVolumeProgressiveLoader, OrthancRestApiCommand::SuccessMessage>
-      (*this, &OrthancSeriesVolumeProgressiveLoader::LoadGeometry));
+    // TODO => Move this out of constructor
+    Register<OrthancRestApiCommand::SuccessMessage>
+      (oracleObservable, &OrthancSeriesVolumeProgressiveLoader::LoadGeometry);
 
-    oracleObservable.RegisterObserverCallback(
-      new Callable<OrthancSeriesVolumeProgressiveLoader, GetOrthancImageCommand::SuccessMessage>
-      (*this, &OrthancSeriesVolumeProgressiveLoader::LoadBestQualitySliceContent));
+    Register<GetOrthancImageCommand::SuccessMessage>
+      (oracleObservable, &OrthancSeriesVolumeProgressiveLoader::LoadBestQualitySliceContent);
 
-    oracleObservable.RegisterObserverCallback(
-      new Callable<OrthancSeriesVolumeProgressiveLoader, GetOrthancWebViewerJpegCommand::SuccessMessage>
-      (*this, &OrthancSeriesVolumeProgressiveLoader::LoadJpegSliceContent));
+    Register<GetOrthancWebViewerJpegCommand::SuccessMessage>
+      (oracleObservable, &OrthancSeriesVolumeProgressiveLoader::LoadJpegSliceContent);
   }
 
   OrthancSeriesVolumeProgressiveLoader::~OrthancSeriesVolumeProgressiveLoader()
   {
-    oracleObservable_.Unregister(this);
     LOG(TRACE) << "OrthancSeriesVolumeProgressiveLoader::~OrthancSeriesVolumeProgressiveLoader()";
   }
 
@@ -485,7 +481,8 @@
       command->SetUri("/series/" + seriesId + "/instances-tags");
 
 //      LOG(TRACE) << "OrthancSeriesVolumeProgressiveLoader::LoadSeries about to call oracle_.Schedule";
-      oracle_.Schedule(*this, command.release());
+      boost::shared_ptr<IObserver> observer(GetSharedObserver());
+      oracle_.Schedule(observer, command.release());
 //      LOG(TRACE) << "OrthancSeriesVolumeProgressiveLoader::LoadSeries called oracle_.Schedule";
     }
   }
--- a/Framework/Loaders/OrthancSeriesVolumeProgressiveLoader.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Loaders/OrthancSeriesVolumeProgressiveLoader.h	Wed Oct 23 11:04:47 2019 +0200
@@ -22,7 +22,7 @@
 #pragma once
 
 #include "../Messages/IObservable.h"
-#include "../Messages/IObserver.h"
+#include "../Messages/ObserverBase.h"
 #include "../Oracle/GetOrthancImageCommand.h"
 #include "../Oracle/GetOrthancWebViewerJpegCommand.h"
 #include "../Oracle/IOracle.h"
@@ -42,7 +42,7 @@
     is stored in a Dicom series.
   */
   class OrthancSeriesVolumeProgressiveLoader : 
-    public IObserver,
+    public ObserverBase<OrthancSeriesVolumeProgressiveLoader>,
     public IObservable,
     public IVolumeSlicer,
     public IGeometryProvider
@@ -106,7 +106,6 @@
     void LoadJpegSliceContent(const GetOrthancWebViewerJpegCommand::SuccessMessage& message);
 
     IOracle&                                      oracle_;
-    IObservable&                                  oracleObservable_;
     bool                                          active_;
     unsigned int                                  simultaneousDownloads_;
     SeriesGeometry                                seriesGeometry_;
--- a/Framework/Messages/ICallable.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Messages/ICallable.h	Wed Oct 23 11:04:47 2019 +0200
@@ -22,20 +22,20 @@
 #pragma once
 
 #include "IMessage.h"
+#include "IObserver.h"
 
 #include <Core/Logging.h>
 
 #include <boost/noncopyable.hpp>
+#include <boost/weak_ptr.hpp>
 
 #include <string>
 
-namespace OrthancStone {
-
-  class IObserver;
-
+namespace OrthancStone 
+{
   // This is referencing an object and member function that can be notified
   // by an IObservable.  The object must derive from IO
-  // The member functions must be of type "void Function(const IMessage& message)" or reference a derived class of IMessage
+  // The member functions must be of type "void Method(const IMessage& message)" or reference a derived class of IMessage
   class ICallable : public boost::noncopyable
   {
   public:
@@ -47,11 +47,14 @@
 
     virtual const MessageIdentifier& GetMessageIdentifier() = 0;
 
-    virtual IObserver* GetObserver() const = 0;
+    // TODO - Is this needed?
+    virtual boost::weak_ptr<IObserver> GetObserver() const = 0;
   };
 
+
+  // TODO - Remove this class
   template <typename TMessage>
-  class MessageHandler: public ICallable
+  class MessageHandler : public ICallable
   {
   };
 
@@ -61,47 +64,28 @@
   class Callable : public MessageHandler<TMessage>
   {
   private:
-    typedef void (TObserver::* MemberFunction) (const TMessage&);
+    typedef void (TObserver::* MemberMethod) (const TMessage&);
 
-    TObserver&         observer_;
-    MemberFunction     function_;
-    std::string        observerFingerprint_;
+    boost::weak_ptr<IObserver>  observer_;
+    MemberMethod                function_;
 
   public:
-    Callable(TObserver& observer,
-             MemberFunction function) :
+    Callable(boost::shared_ptr<TObserver> observer,
+             MemberMethod function) :
       observer_(observer),
-      function_(function),
-      observerFingerprint_(observer.GetFingerprint())
-    {
-    }
-
-    void ApplyInternal(const TMessage& message)
+      function_(function)
     {
-      std::string currentFingerprint(observer_.GetFingerprint());
-      if (observerFingerprint_ != currentFingerprint)
-      {
-        LOG(TRACE) << "The observer at address " << 
-          std::hex << &observer_ << std::dec << 
-          ") has a different fingerprint than the one recorded at callback " <<
-          "registration time. This means that it is not the same object as " <<
-          "the one recorded, even though their addresses are the same. " <<
-          "Callback will NOT be sent!";
-        LOG(TRACE) << " recorded fingerprint = " << observerFingerprint_ << 
-          " current fingerprint = " << currentFingerprint;
-      }
-      else
-      {
-        LOG(TRACE) << "The recorded fingerprint is " << observerFingerprint_
-          << " and the current fingerprint is " << currentFingerprint
-          << " -- callable will be called.";
-        (observer_.*function_) (message);
-      }
     }
 
     virtual void Apply(const IMessage& message)
     {
-      ApplyInternal(dynamic_cast<const TMessage&>(message));
+      boost::shared_ptr<IObserver> lock(observer_);
+      if (lock)
+      {
+        TObserver& observer = dynamic_cast<TObserver&>(*lock);
+        const TMessage& typedMessage = dynamic_cast<const TMessage&>(message);
+        (observer.*function_) (typedMessage);
+      }
     }
 
     virtual const MessageIdentifier& GetMessageIdentifier()
@@ -109,41 +93,9 @@
       return TMessage::GetStaticIdentifier();
     }
 
-    virtual IObserver* GetObserver() const
+    virtual boost::weak_ptr<IObserver> GetObserver() const
     {
-      return &observer_;
+      return observer_;
     }
   };
-
-#if 0 /* __cplusplus >= 201103L*/
-
-#include <functional>
-
-  template <typename TMessage>
-  class LambdaCallable : public MessageHandler<TMessage>
-  {
-  private:
-
-    IObserver&      observer_;
-    std::function<void (const TMessage&)> lambda_;
-
-  public:
-    LambdaCallable(IObserver& observer,
-                    std::function<void (const TMessage&)> lambdaFunction) :
-             observer_(observer),
-             lambda_(lambdaFunction)
-    {
-    }
-
-    virtual void Apply(const IMessage& message)
-    {
-      lambda_(dynamic_cast<const TMessage&>(message));
-    }
-
-    virtual IObserver* GetObserver() const
-    {
-      return &observer_;
-    }
-  };
-#endif //__cplusplus >= 201103L
 }
--- a/Framework/Messages/IMessage.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Messages/IMessage.h	Wed Oct 23 11:04:47 2019 +0200
@@ -33,6 +33,12 @@
     const char*  file_;
     int          line_;
 
+    bool IsEqual(const MessageIdentifier& other) const
+    {
+      return (line_ == other.line_ &&
+              strcmp(file_, other.file_) == 0);
+    }
+
   public:
     MessageIdentifier(const char* file,
                       int line) :
@@ -62,6 +68,16 @@
         return strcmp(file_, other.file_) < 0;
       }
     }
+
+    bool operator== (const MessageIdentifier& other) const
+    {
+      return IsEqual(other);
+    }
+
+    bool operator!= (const MessageIdentifier& other) const
+    {
+      return !IsEqual(other);
+    }
   };
 
     
--- a/Framework/Messages/IMessageEmitter.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Messages/IMessageEmitter.h	Wed Oct 23 11:04:47 2019 +0200
@@ -24,6 +24,8 @@
 #include "IObserver.h"
 #include "IMessage.h"
 
+#include <boost/weak_ptr.hpp>
+
 namespace OrthancStone
 {
   /**
@@ -39,7 +41,7 @@
     {
     }
 
-    virtual void EmitMessage(const IObserver& observer,
+    virtual void EmitMessage(boost::weak_ptr<IObserver>& observer,
                              const IMessage& message) = 0;
   };
 }
--- a/Framework/Messages/IObservable.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Messages/IObservable.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -40,20 +40,10 @@
         delete *it2;
       }
     }
-
-    // unregister the forwarders but don't delete them (they'll be
-    // deleted by the observable they are observing as any other
-    // callable)
-    for (Forwarders::iterator it = forwarders_.begin();
-         it != forwarders_.end(); ++it)
-    {
-      IMessageForwarder* fw = *it;
-      broker_.Unregister(dynamic_cast<IObserver&>(*fw));
-    }
   }
   
 
-  void IObservable::RegisterObserverCallback(ICallable* callable)
+  void IObservable::RegisterCallable(ICallable* callable)
   {
     if (callable == NULL)
     {
@@ -64,30 +54,6 @@
     callables_[id].insert(callable);
   }
 
-  void IObservable::Unregister(IObserver *observer)
-  {
-    LOG(TRACE) << "IObservable::Unregister for IObserver at addr: "
-      << std::hex << observer << std::dec;
-    // delete all callables from this observer
-    for (Callables::iterator itCallableSet = callables_.begin();
-         itCallableSet != callables_.end(); ++itCallableSet)
-    {
-      for (std::set<ICallable*>::const_iterator
-             itCallable = itCallableSet->second.begin(); itCallable != itCallableSet->second.end(); )
-      {
-        if ((*itCallable)->GetObserver() == observer)
-        {
-          LOG(TRACE) << "  ** IObservable::Unregister : deleting callable: "
-            << std::hex << (*itCallable) << std::dec;
-          delete *itCallable;
-          itCallableSet->second.erase(itCallable++);
-        }
-        else
-          ++itCallable;
-      }
-    }
-  }
-  
   void IObservable::EmitMessageInternal(const IObserver* receiver,
                                         const IMessage& message)
   {
@@ -102,15 +68,21 @@
       {
         assert(*it != NULL);
 
-        const IObserver* observer = (*it)->GetObserver();
-        if (broker_.IsActive(*observer))
+        boost::shared_ptr<IObserver> observer((*it)->GetObserver().lock());
+
+        if (observer)
         {
           if (receiver == NULL ||    // Are we broadcasting?
-              observer == receiver)  // Not broadcasting, but this is the receiver
+              observer.get() == receiver)  // Not broadcasting, but this is the receiver
           {
             (*it)->Apply(message);
           }
         }
+        else
+        {
+          // TODO => Remove "it" from the list of callables => This
+          // allows to suppress the need for "Unregister()"
+        }
       }
     }
   }
@@ -122,21 +94,16 @@
   }
 
   
-  void IObservable::EmitMessage(const IObserver& observer,
+  void IObservable::EmitMessage(boost::weak_ptr<IObserver>& observer,
                                 const IMessage& message)
   {
     LOG(TRACE) << "IObservable::EmitMessage observer = "
       << std::hex << &observer << std::dec;
-    EmitMessageInternal(&observer, message);
-  }
-  
-  void IObservable::RegisterForwarder(IMessageForwarder* forwarder)
-  {
-    if (forwarder == NULL)
+
+    boost::shared_ptr<IObserver> lock(observer.lock());
+    if (lock)
     {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
+      EmitMessageInternal(lock.get(), message);
     }
-    
-    forwarders_.insert(forwarder);
   }
 }
--- a/Framework/Messages/IObservable.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Messages/IObservable.h	Wed Oct 23 11:04:47 2019 +0200
@@ -24,8 +24,6 @@
 #include "../StoneEnumerations.h"
 #include "ICallable.h"
 #include "IObserver.h"
-#include "MessageBroker.h"
-#include "MessageForwarder.h"
 
 #include <set>
 #include <map>
@@ -37,39 +35,20 @@
   private:
     typedef std::map<MessageIdentifier, std::set<ICallable*> >  Callables;
 
-    typedef std::set<IMessageForwarder*>     Forwarders;
-
-    MessageBroker&  broker_;
     Callables       callables_;
-    Forwarders      forwarders_;
 
     void EmitMessageInternal(const IObserver* receiver,
                              const IMessage& message);
 
   public:
-    IObservable(MessageBroker& broker) :
-      broker_(broker)
-    {
-    }
-
     virtual ~IObservable();
 
-    MessageBroker& GetBroker() const
-    {
-      return broker_;
-    }
-
-    // Takes ownsership
-    void RegisterObserverCallback(ICallable* callable);
-
-    void Unregister(IObserver* observer);
+    // Takes ownsership of the callable
+    void RegisterCallable(ICallable* callable);
 
     void BroadcastMessage(const IMessage& message);
 
-    void EmitMessage(const IObserver& observer,
+    void EmitMessage(boost::weak_ptr<IObserver>& observer,
                      const IMessage& message);
-
-    // Takes ownsership
-    void RegisterForwarder(IMessageForwarder* forwarder);
   };
 }
--- a/Framework/Messages/IObserver.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "IObserver.h"
-
-#include "IMessage.h"
-#include "../StoneException.h"
-
-#include <Core/Logging.h>
-#include <Core/Toolbox.h>
-
-namespace OrthancStone 
-{
-  IObserver::IObserver(MessageBroker& broker)
-    : broker_(broker)
-    , fingerprint_()
-  {
-    // we store the fingerprint_ as a char array to avoid problems when
-    // reading it in a deceased object.
-    // remember this is panic-level code to track zombie object usage
-    std::string fingerprint = Orthanc::Toolbox::GenerateUuid();
-    const char* fingerprintRaw = fingerprint.c_str();
-    memcpy(fingerprint_, fingerprintRaw, 37);
-    broker_.Register(*this);
-  }
-
-
-  IObserver::~IObserver()
-  {
-    try
-    {
-      LOG(TRACE) << "IObserver(" << std::hex << this << std::dec << ")::~IObserver : fingerprint_ == " << fingerprint_;
-      const char* deadMarker = "deadbeef-dead-dead-0000-0000deadbeef";
-      ORTHANC_ASSERT(strlen(deadMarker) == 36);
-      memcpy(fingerprint_, deadMarker, 37);
-      broker_.Unregister(*this);
-    }
-    catch (const Orthanc::OrthancException& e)
-    {
-      if (e.HasDetails())
-      {
-        LOG(ERROR) << "OrthancException in ~IObserver: " << e.What() << " Details: " << e.GetDetails();
-      }
-      else
-      {
-        LOG(ERROR) << "OrthancException in ~IObserver: " << e.What();
-      }
-    }
-    catch (const std::exception& e)
-    {
-      LOG(ERROR) << "std::exception in ~IObserver: " << e.what();
-    }
-    catch (...)
-    {
-      LOG(ERROR) << "Unknown exception in ~IObserver";
-    }
-  }
-
-
-  bool IObserver::DoesFingerprintLookGood() const
-  {
-    for (size_t i = 0; i < 36; ++i) {
-      bool ok = false;
-      if (fingerprint_[i] >= 'a' && fingerprint_[i] <= 'f')
-        ok = true;
-      if (fingerprint_[i] >= '0' && fingerprint_[i] <= '9')
-        ok = true;
-      if (fingerprint_[i] == '-')
-        ok = true;
-      if (!ok)
-        return false;
-    }
-    return fingerprint_[36] == 0;
-  }
-}
--- a/Framework/Messages/IObserver.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Messages/IObserver.h	Wed Oct 23 11:04:47 2019 +0200
@@ -21,33 +21,19 @@
 
 #pragma once
 
-#include "MessageBroker.h"
+#include <boost/noncopyable.hpp>
 
 namespace OrthancStone 
 {
   class IObserver : public boost::noncopyable
   {
-  private:
-    MessageBroker&  broker_;
-    // the following is a UUID that is used to disambiguate different observers
-    // that may have the same address
-    char     fingerprint_[37];
-
   public:
-    IObserver(MessageBroker& broker);
-
-    virtual ~IObserver();
-
-    const char* GetFingerprint() const
+    IObserver()
     {
-      return fingerprint_;
     }
 
-    bool DoesFingerprintLookGood() const;
-
-    MessageBroker& GetBroker() const
+    virtual ~IObserver()
     {
-      return broker_;
     }
   };
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Messages/LockingEmitter.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -0,0 +1,40 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "LockingEmitter.h"
+
+#include <Core/OrthancException.h>
+
+namespace OrthancStone
+{
+  void LockingEmitter::EmitMessage(boost::weak_ptr<IObserver>& observer,
+                                   const IMessage& message)
+  {
+    try
+    {
+      boost::unique_lock<boost::shared_mutex>  lock(mutex_);
+      oracleObservable_.EmitMessage(observer, message);
+    }
+    catch (Orthanc::OrthancException& e)
+    {
+      LOG(ERROR) << "Exception while emitting a message: " << e.What();
+    }
+  }
+}
--- a/Framework/Messages/LockingEmitter.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Messages/LockingEmitter.h	Wed Oct 23 11:04:47 2019 +0200
@@ -26,7 +26,9 @@
 #include "IMessageEmitter.h"
 #include "IObservable.h"
 
-#include <boost/thread.hpp>
+#include <Core/Enumerations.h>  // For ORTHANC_OVERRIDE
+
+#include <boost/thread/shared_mutex.hpp>
 
 namespace OrthancStone
 {
@@ -43,33 +45,11 @@
   {
   private:
     boost::shared_mutex  mutex_;
-    MessageBroker        broker_;
     IObservable          oracleObservable_;
 
   public:
-    LockingEmitter() :
-      oracleObservable_(broker_)
-    {
-    }
-
-    MessageBroker& GetBroker()
-    {
-      return broker_;
-    }
-
-    virtual void EmitMessage(const IObserver& observer,
-      const IMessage& message) ORTHANC_OVERRIDE
-    {
-      try
-      {
-        boost::unique_lock<boost::shared_mutex>  lock(mutex_);
-        oracleObservable_.EmitMessage(observer, message);
-      }
-      catch (Orthanc::OrthancException& e)
-      {
-        LOG(ERROR) << "Exception while emitting a message: " << e.What();
-      }
-    }
+    virtual void EmitMessage(boost::weak_ptr<IObserver>& observer,
+                             const IMessage& message) ORTHANC_OVERRIDE;
 
 
     class ReaderLock : public boost::noncopyable
@@ -80,8 +60,8 @@
 
     public:
       ReaderLock(LockingEmitter& that) :
-        that_(that),
-        lock_(that.mutex_)
+      that_(that),
+      lock_(that.mutex_)
       {
       }
     };
@@ -95,16 +75,11 @@
 
     public:
       WriterLock(LockingEmitter& that) :
-        that_(that),
-        lock_(that.mutex_)
+      that_(that),
+      lock_(that.mutex_)
       {
       }
 
-      MessageBroker& GetBroker()
-      {
-        return that_.broker_;
-      }
-
       IObservable& GetOracleObservable()
       {
         return that_.oracleObservable_;
--- a/Framework/Messages/MessageBroker.h	Tue Oct 22 17:51:25 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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/>.
- **/
-
-#pragma once
-
-#include "boost/noncopyable.hpp"
-
-#include <set>
-
-namespace OrthancStone
-{
-  class IObserver;
-
-  /*
-   * This is a central message broker.  It keeps track of all observers and knows
-   * when an observer is deleted.
-   * This way, it can prevent an observable to send a message to a deleted observer.
-   */
-  class MessageBroker : public boost::noncopyable
-  {
-  private:
-    std::set<const IObserver*> activeObservers_;  // the list of observers that are currently alive (that have not been deleted)
-
-  public:
-    MessageBroker()
-    {
-    }
-
-    void Register(const IObserver& observer)
-    {
-      activeObservers_.insert(&observer);
-    }
-
-    void Unregister(const IObserver& observer)
-    {
-      activeObservers_.erase(&observer);
-    }
-
-    bool IsActive(const IObserver& observer)
-    {
-      return activeObservers_.find(&observer) != activeObservers_.end();
-    }
-  };
-}
--- a/Framework/Messages/MessageForwarder.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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 "MessageForwarder.h"
-
-#include "IObservable.h"
-
-namespace OrthancStone
-{
-
-  void IMessageForwarder::ForwardMessageInternal(const IMessage& message)
-  {
-    emitter_.BroadcastMessage(message);
-  }
-
-  void IMessageForwarder::RegisterForwarderInEmitter()
-  {
-    emitter_.RegisterForwarder(this);
-  }
-}
--- a/Framework/Messages/MessageForwarder.h	Tue Oct 22 17:51:25 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 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/>.
- **/
-
-
-#pragma once
-
-#include "ICallable.h"
-#include "IObserver.h"
-
-#include <boost/noncopyable.hpp>
-
-namespace OrthancStone
-{
-
-  class IObservable;
-
-  class IMessageForwarder : public IObserver
-  {
-    IObservable& emitter_;
-  public:
-    IMessageForwarder(MessageBroker& broker, IObservable& emitter)
-      : IObserver(broker),
-        emitter_(emitter)
-    {}
-    virtual ~IMessageForwarder() {}
-
-  protected:
-    void ForwardMessageInternal(const IMessage& message);
-    void RegisterForwarderInEmitter();
-
-  };
-
-  /* When an Observer (B) simply needs to re-emit a message it has received, instead of implementing
-   * a specific member function to forward the message, it can create a MessageForwarder.
-   * The MessageForwarder will re-emit the message "in the name of (B)"
-   *
-   * Consider the chain where
-   * A is an observable
-   * |
-   * B is an observer of A and observable
-   * |
-   * C is an observer of B and knows that B is re-emitting many messages from A
-   *
-   * instead of implementing a callback, B will create a MessageForwarder that will emit the messages in his name:
-   * A.RegisterObserverCallback(new MessageForwarder<A::MessageType>(broker, *this)  // where "this" is B
-   *
-   * in C:
-   * B.RegisterObserverCallback(new Callable<C, A:MessageTyper>(*this, &B::MyCallback))   // where "this" is C
-   */
-  template<typename TMessage>
-  class MessageForwarder : public IMessageForwarder, public Callable<MessageForwarder<TMessage>, TMessage>
-  {
-  public:
-    MessageForwarder(MessageBroker& broker,
-                     IObservable& emitter // the object that will emit the messages to forward
-                     )
-      : IMessageForwarder(broker, emitter),
-        Callable<MessageForwarder<TMessage>, TMessage>(*this, &MessageForwarder::ForwardMessage)
-    {
-      RegisterForwarderInEmitter();
-    }
-
-protected:
-    void ForwardMessage(const TMessage& message)
-    {
-      ForwardMessageInternal(message);
-    }
-
-  };
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Messages/ObserverBase.h	Wed Oct 23 11:04:47 2019 +0200
@@ -0,0 +1,68 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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/>.
+ **/
+
+
+#pragma once
+
+#include "ICallable.h"
+#include "IObserver.h"
+#include "IObservable.h"
+
+#include <Core/OrthancException.h>
+
+#include <boost/enable_shared_from_this.hpp>
+
+namespace OrthancStone 
+{
+  template <typename TObserver>
+  class ObserverBase : 
+    public IObserver,
+    public boost::enable_shared_from_this<TObserver>
+  {
+  public:
+    boost::shared_ptr<TObserver> GetSharedObserver()
+    {
+      try
+      {
+        return this->shared_from_this();
+      }
+      catch (boost::bad_weak_ptr&)
+      {
+        throw Orthanc::OrthancException(
+          Orthanc::ErrorCode_InternalError,
+          "Cannot get a shared pointer to an observer from its constructor, "
+          "or the observer is not created as a shared pointer");
+      }
+    }
+
+    template <typename TMessage>
+    ICallable* CreateCallable(void (TObserver::* MemberMethod) (const TMessage&))
+    {
+      return new Callable<TObserver, TMessage>(GetSharedObserver(), MemberMethod);
+    }
+
+    template <typename TMessage>
+    void Register(IObservable& observable,
+                  void (TObserver::* MemberMethod) (const TMessage&))
+    {
+      observable.RegisterCallable(CreateCallable(MemberMethod));
+    }
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Oracle/CustomOracleCommand.h	Wed Oct 23 11:04:47 2019 +0200
@@ -0,0 +1,40 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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/>.
+ **/
+
+
+#pragma once
+
+#include "IOracleRunner.h"
+
+namespace OrthancStone
+{
+  class CustomOracleCommand : public IOracleCommand
+  {
+  public:
+    virtual Type GetType() const
+    {
+      return Type_Custom;
+    }
+
+    virtual void Execute(IMessageEmitter& emitter,
+                         boost::weak_ptr<IObserver>& receiver,
+                         IOracleRunner& runner) = 0;
+  };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Oracle/GenericOracleRunner.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -0,0 +1,239 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "GenericOracleRunner.h"
+
+#include "CustomOracleCommand.h"
+#include "GetOrthancImageCommand.h"
+#include "GetOrthancWebViewerJpegCommand.h"
+#include "HttpCommand.h"
+#include "OracleCommandExceptionMessage.h"
+#include "OrthancRestApiCommand.h"
+
+#include <Core/Compression/GzipCompressor.h>
+#include <Core/HttpClient.h>
+#include <Core/OrthancException.h>
+#include <Core/Toolbox.h>
+
+namespace OrthancStone
+{
+  static void CopyHttpHeaders(Orthanc::HttpClient& client,
+                              const Orthanc::HttpClient::HttpHeaders& headers)
+  {
+    for (Orthanc::HttpClient::HttpHeaders::const_iterator
+           it = headers.begin(); it != headers.end(); it++ )
+    {
+      client.AddHeader(it->first, it->second);
+    }
+  }
+
+
+  static void DecodeAnswer(std::string& answer,
+                           const Orthanc::HttpClient::HttpHeaders& headers)
+  {
+    Orthanc::HttpCompression contentEncoding = Orthanc::HttpCompression_None;
+
+    for (Orthanc::HttpClient::HttpHeaders::const_iterator it = headers.begin(); 
+         it != headers.end(); ++it)
+    {
+      std::string s;
+      Orthanc::Toolbox::ToLowerCase(s, it->first);
+
+      if (s == "content-encoding")
+      {
+        if (it->second == "gzip")
+        {
+          contentEncoding = Orthanc::HttpCompression_Gzip;
+        }
+        else 
+        {
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol,
+                                          "Unsupported HTTP Content-Encoding: " + it->second);
+        }
+
+        break;
+      }
+    }
+
+    if (contentEncoding == Orthanc::HttpCompression_Gzip)
+    {
+      std::string compressed;
+      answer.swap(compressed);
+          
+      Orthanc::GzipCompressor compressor;
+      compressor.Uncompress(answer, compressed.c_str(), compressed.size());
+
+      LOG(INFO) << "Uncompressing gzip Encoding: from " << compressed.size()
+                << " to " << answer.size() << " bytes";
+    }
+  }
+
+
+  static void Execute(IMessageEmitter& emitter,
+                      boost::weak_ptr<IObserver>& receiver,
+                      const HttpCommand& command)
+  {
+    Orthanc::HttpClient client;
+    client.SetUrl(command.GetUrl());
+    client.SetMethod(command.GetMethod());
+    client.SetTimeout(command.GetTimeout());
+
+    CopyHttpHeaders(client, command.GetHttpHeaders());
+
+    if (command.HasCredentials())
+    {
+      client.SetCredentials(command.GetUsername().c_str(), command.GetPassword().c_str());
+    }
+
+    if (command.GetMethod() == Orthanc::HttpMethod_Post ||
+        command.GetMethod() == Orthanc::HttpMethod_Put)
+    {
+      client.SetBody(command.GetBody());
+    }
+
+    std::string answer;
+    Orthanc::HttpClient::HttpHeaders answerHeaders;
+    client.ApplyAndThrowException(answer, answerHeaders);
+
+    DecodeAnswer(answer, answerHeaders);
+
+    HttpCommand::SuccessMessage message(command, answerHeaders, answer);
+    emitter.EmitMessage(receiver, message);
+  }
+
+
+  static void Execute(IMessageEmitter& emitter,
+                      const Orthanc::WebServiceParameters& orthanc,
+                      boost::weak_ptr<IObserver>& receiver,
+                      const OrthancRestApiCommand& command)
+  {
+    Orthanc::HttpClient client(orthanc, command.GetUri());
+    client.SetMethod(command.GetMethod());
+    client.SetTimeout(command.GetTimeout());
+
+    CopyHttpHeaders(client, command.GetHttpHeaders());
+
+    if (command.GetMethod() == Orthanc::HttpMethod_Post ||
+        command.GetMethod() == Orthanc::HttpMethod_Put)
+    {
+      client.SetBody(command.GetBody());
+    }
+
+    std::string answer;
+    Orthanc::HttpClient::HttpHeaders answerHeaders;
+    client.ApplyAndThrowException(answer, answerHeaders);
+
+    DecodeAnswer(answer, answerHeaders);
+
+    OrthancRestApiCommand::SuccessMessage message(command, answerHeaders, answer);
+    emitter.EmitMessage(receiver, message);
+  }
+
+
+  static void Execute(IMessageEmitter& emitter,
+                      const Orthanc::WebServiceParameters& orthanc,
+                      boost::weak_ptr<IObserver>& receiver,
+                      const GetOrthancImageCommand& command)
+  {
+    Orthanc::HttpClient client(orthanc, command.GetUri());
+    client.SetTimeout(command.GetTimeout());
+
+    CopyHttpHeaders(client, command.GetHttpHeaders());
+    
+    std::string answer;
+    Orthanc::HttpClient::HttpHeaders answerHeaders;
+    client.ApplyAndThrowException(answer, answerHeaders);
+
+    DecodeAnswer(answer, answerHeaders);
+
+    command.ProcessHttpAnswer(emitter, receiver, answer, answerHeaders);
+  }
+
+
+  static void Execute(IMessageEmitter& emitter,
+                      const Orthanc::WebServiceParameters& orthanc,
+                      boost::weak_ptr<IObserver>& receiver,
+                      const GetOrthancWebViewerJpegCommand& command)
+  {
+    Orthanc::HttpClient client(orthanc, command.GetUri());
+    client.SetTimeout(command.GetTimeout());
+
+    CopyHttpHeaders(client, command.GetHttpHeaders());
+
+    std::string answer;
+    Orthanc::HttpClient::HttpHeaders answerHeaders;
+    client.ApplyAndThrowException(answer, answerHeaders);
+
+    DecodeAnswer(answer, answerHeaders);
+
+    command.ProcessHttpAnswer(emitter, receiver, answer);
+  }
+
+
+  void GenericOracleRunner::Run(boost::weak_ptr<IObserver>& receiver,
+                                IOracleCommand& command)
+  {
+    try
+    {
+      switch (command.GetType())
+      {
+        case IOracleCommand::Type_Sleep:
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_BadParameterType,
+                                          "Sleep command cannot be executed by the runner");
+          break;
+
+        case IOracleCommand::Type_Http:
+          Execute(emitter_, receiver, dynamic_cast<const HttpCommand&>(command));
+          break;
+
+        case IOracleCommand::Type_OrthancRestApi:
+          Execute(emitter_, orthanc_, receiver, dynamic_cast<const OrthancRestApiCommand&>(command));
+          break;
+
+        case IOracleCommand::Type_GetOrthancImage:
+          Execute(emitter_, orthanc_, receiver, dynamic_cast<const GetOrthancImageCommand&>(command));
+          break;
+
+        case IOracleCommand::Type_GetOrthancWebViewerJpeg:
+          Execute(emitter_, orthanc_, receiver, dynamic_cast<const GetOrthancWebViewerJpegCommand&>(command));
+          break;
+
+        case IOracleCommand::Type_Custom:
+          dynamic_cast<CustomOracleCommand&>(command).Execute(emitter_, receiver, *this);
+          break;
+
+        default:
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
+      }
+    }
+    catch (Orthanc::OrthancException& e)
+    {
+      LOG(ERROR) << "Exception within the oracle: " << e.What();
+      emitter_.EmitMessage(receiver, OracleCommandExceptionMessage(command, e));
+    }
+    catch (...)
+    {
+      LOG(ERROR) << "Threaded exception within the oracle";
+      emitter_.EmitMessage(receiver, OracleCommandExceptionMessage
+                           (command, Orthanc::ErrorCode_InternalError));
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Oracle/GenericOracleRunner.h	Wed Oct 23 11:04:47 2019 +0200
@@ -0,0 +1,49 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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/>.
+ **/
+
+
+#pragma once
+
+#include "../Messages/IMessageEmitter.h"
+#include "IOracleRunner.h"
+
+#include <Core/Enumerations.h>  // For ORTHANC_OVERRIDE
+#include <Core/WebServiceParameters.h>
+
+namespace OrthancStone
+{
+  class GenericOracleRunner : public IOracleRunner
+  {
+  private:
+    IMessageEmitter&                      emitter_;
+    const Orthanc::WebServiceParameters&  orthanc_;
+
+  public:
+    GenericOracleRunner(IMessageEmitter&  emitter,
+                        const Orthanc::WebServiceParameters& orthanc) :
+      emitter_(emitter),
+      orthanc_(orthanc)
+    {
+    }
+
+    virtual void Run(boost::weak_ptr<IObserver>& receiver,
+                     IOracleCommand& command) ORTHANC_OVERRIDE;
+  };
+}
--- a/Framework/Oracle/GetOrthancImageCommand.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Oracle/GetOrthancImageCommand.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -83,7 +83,7 @@
   }
 
   void GetOrthancImageCommand::ProcessHttpAnswer(IMessageEmitter& emitter,
-                                                 const IObserver& receiver,
+                                                 boost::weak_ptr<IObserver>& receiver,
                                                  const std::string& answer,
                                                  const HttpHeaders& answerHeaders) const
   {
--- a/Framework/Oracle/GetOrthancImageCommand.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Oracle/GetOrthancImageCommand.h	Wed Oct 23 11:04:47 2019 +0200
@@ -112,7 +112,7 @@
     }
 
     void ProcessHttpAnswer(IMessageEmitter& emitter,
-                           const IObserver& receiver,
+                           boost::weak_ptr<IObserver>& receiver,
                            const std::string& answer,
                            const HttpHeaders& answerHeaders) const;
   };
--- a/Framework/Oracle/GetOrthancWebViewerJpegCommand.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Oracle/GetOrthancWebViewerJpegCommand.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -77,7 +77,7 @@
 
 
   void GetOrthancWebViewerJpegCommand::ProcessHttpAnswer(IMessageEmitter& emitter,
-                                                         const IObserver& receiver,
+                                                         boost::weak_ptr<IObserver>& receiver,
                                                          const std::string& answer) const
   {
     // This code comes from older "OrthancSlicesLoader::ParseSliceImageJpeg()"
--- a/Framework/Oracle/GetOrthancWebViewerJpegCommand.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Oracle/GetOrthancWebViewerJpegCommand.h	Wed Oct 23 11:04:47 2019 +0200
@@ -129,7 +129,7 @@
     std::string GetUri() const;
 
     void ProcessHttpAnswer(IMessageEmitter& emitter,
-                           const IObserver& receiver,
+                           boost::weak_ptr<IObserver>& receiver,
                            const std::string& answer) const;
   };
 }
--- a/Framework/Oracle/HttpCommand.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Oracle/HttpCommand.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -76,4 +76,30 @@
       throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
     }
   }
+
+
+  const std::string& HttpCommand::GetUsername() const
+  {
+    if (HasCredentials())
+    {
+      return username_;
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+  }
+
+
+  const std::string& HttpCommand::GetPassword() const
+  {
+    if (HasCredentials())
+    {
+      return password_;
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+  }
 }
--- a/Framework/Oracle/HttpCommand.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Oracle/HttpCommand.h	Wed Oct 23 11:04:47 2019 +0200
@@ -69,6 +69,8 @@
     std::string          body_;
     HttpHeaders          headers_;
     unsigned int         timeout_;
+    std::string          username_;
+    std::string          password_;
 
   public:
     HttpCommand();
@@ -137,5 +139,27 @@
     {
       return timeout_;
     }
+
+    void SetCredentials(const std::string& username,
+                        const std::string& password)
+    {
+      username_ = username;
+      password_ = password;
+    }
+
+    void ClearCredentials()
+    {
+      username_.clear();
+      password_.clear();
+    }
+
+    bool HasCredentials() const
+    {
+      return !username_.empty();
+    }
+
+    const std::string& GetUsername() const;
+
+    const std::string& GetPassword() const;
   };
 }
--- a/Framework/Oracle/IOracle.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Oracle/IOracle.h	Wed Oct 23 11:04:47 2019 +0200
@@ -22,7 +22,9 @@
 #pragma once
 
 #include "../Messages/IObserver.h"
-#include "IOracleCommand.h"
+#include "IOracleRunner.h"
+
+#include <boost/shared_ptr.hpp>
 
 namespace OrthancStone
 {
@@ -33,7 +35,7 @@
     {
     }
 
-    virtual void Schedule(const IObserver& receiver,
+    virtual void Schedule(boost::shared_ptr<IObserver>& receiver,
                           IOracleCommand* command) = 0;  // Takes ownership
   };
 }
--- a/Framework/Oracle/IOracleCommand.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Oracle/IOracleCommand.h	Wed Oct 23 11:04:47 2019 +0200
@@ -34,7 +34,8 @@
       Type_Sleep,
       Type_OrthancRestApi,
       Type_GetOrthancImage,
-      Type_GetOrthancWebViewerJpeg
+      Type_GetOrthancWebViewerJpeg,
+      Type_Custom
     };
 
     virtual ~IOracleCommand()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Oracle/IOracleRunner.h	Wed Oct 23 11:04:47 2019 +0200
@@ -0,0 +1,40 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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/>.
+ **/
+
+
+#pragma once
+
+#include "IOracleCommand.h"
+
+#include <boost/weak_ptr.hpp>
+
+namespace OrthancStone
+{
+  class IOracleRunner : public boost::noncopyable
+  {
+  public:
+    virtual ~IOracleRunner()
+    {
+    }
+
+    virtual void Run(boost::weak_ptr<IObserver>& receiver,
+                     IOracleCommand& command) = 0;
+  };
+}
--- a/Framework/Oracle/ThreadedOracle.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Oracle/ThreadedOracle.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -21,29 +21,21 @@
 
 #include "ThreadedOracle.h"
 
-#include "GetOrthancImageCommand.h"
-#include "GetOrthancWebViewerJpegCommand.h"
-#include "HttpCommand.h"
-#include "OrthancRestApiCommand.h"
 #include "SleepOracleCommand.h"
-#include "OracleCommandExceptionMessage.h"
 
-#include <Core/Compression/GzipCompressor.h>
-#include <Core/HttpClient.h>
+#include <Core/Logging.h>
 #include <Core/OrthancException.h>
-#include <Core/Toolbox.h>
-
 
 namespace OrthancStone
 {
   class ThreadedOracle::Item : public Orthanc::IDynamicObject
   {
   private:
-    const IObserver&                receiver_;
+    boost::weak_ptr<IObserver>      receiver_;
     std::auto_ptr<IOracleCommand>   command_;
 
   public:
-    Item(const IObserver& receiver,
+    Item(boost::weak_ptr<IObserver> receiver,
          IOracleCommand* command) :
       receiver_(receiver),
       command_(command)
@@ -54,7 +46,7 @@
       }
     }
 
-    const IObserver& GetReceiver() const
+    boost::weak_ptr<IObserver>& GetReceiver()
     {
       return receiver_;
     }
@@ -73,12 +65,12 @@
     class Item
     {
     private:
-      const IObserver&                   receiver_;
+      boost::weak_ptr<IObserver>         receiver_;
       std::auto_ptr<SleepOracleCommand>  command_;
       boost::posix_time::ptime           expiration_;
 
     public:
-      Item(const IObserver& receiver,
+      Item(boost::weak_ptr<IObserver>& receiver,
            SleepOracleCommand* command) :
         receiver_(receiver),
         command_(command)
@@ -123,7 +115,7 @@
       }
     }
 
-    void Add(const IObserver& receiver,
+    void Add(boost::weak_ptr<IObserver>& receiver,
              SleepOracleCommand* command)   // Takes ownership
     {
       boost::mutex::scoped_lock lock(mutex_);
@@ -160,154 +152,6 @@
   };
 
 
-  static void CopyHttpHeaders(Orthanc::HttpClient& client,
-                              const Orthanc::HttpClient::HttpHeaders& headers)
-  {
-    for (Orthanc::HttpClient::HttpHeaders::const_iterator
-           it = headers.begin(); it != headers.end(); it++ )
-    {
-      client.AddHeader(it->first, it->second);
-    }
-  }
-
-
-  static void DecodeAnswer(std::string& answer,
-                           const Orthanc::HttpClient::HttpHeaders& headers)
-  {
-    Orthanc::HttpCompression contentEncoding = Orthanc::HttpCompression_None;
-
-    for (Orthanc::HttpClient::HttpHeaders::const_iterator it = headers.begin(); 
-         it != headers.end(); ++it)
-    {
-      std::string s;
-      Orthanc::Toolbox::ToLowerCase(s, it->first);
-
-      if (s == "content-encoding")
-      {
-        if (it->second == "gzip")
-        {
-          contentEncoding = Orthanc::HttpCompression_Gzip;
-        }
-        else 
-        {
-          throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol,
-                                          "Unsupported HTTP Content-Encoding: " + it->second);
-        }
-
-        break;
-      }
-    }
-
-    if (contentEncoding == Orthanc::HttpCompression_Gzip)
-    {
-      std::string compressed;
-      answer.swap(compressed);
-          
-      Orthanc::GzipCompressor compressor;
-      compressor.Uncompress(answer, compressed.c_str(), compressed.size());
-
-      LOG(INFO) << "Uncompressing gzip Encoding: from " << compressed.size()
-                << " to " << answer.size() << " bytes";
-    }
-  }
-
-
-  static void Execute(IMessageEmitter& emitter,
-                      const IObserver& receiver,
-                      const HttpCommand& command)
-  {
-    Orthanc::HttpClient client;
-    client.SetUrl(command.GetUrl());
-    client.SetMethod(command.GetMethod());
-    client.SetTimeout(command.GetTimeout());
-
-    CopyHttpHeaders(client, command.GetHttpHeaders());
-
-    if (command.GetMethod() == Orthanc::HttpMethod_Post ||
-        command.GetMethod() == Orthanc::HttpMethod_Put)
-    {
-      client.SetBody(command.GetBody());
-    }
-
-    std::string answer;
-    Orthanc::HttpClient::HttpHeaders answerHeaders;
-    client.ApplyAndThrowException(answer, answerHeaders);
-
-    DecodeAnswer(answer, answerHeaders);
-
-    HttpCommand::SuccessMessage message(command, answerHeaders, answer);
-    emitter.EmitMessage(receiver, message);
-  }
-
-
-  static void Execute(IMessageEmitter& emitter,
-                      const Orthanc::WebServiceParameters& orthanc,
-                      const IObserver& receiver,
-                      const OrthancRestApiCommand& command)
-  {
-    Orthanc::HttpClient client(orthanc, command.GetUri());
-    client.SetMethod(command.GetMethod());
-    client.SetTimeout(command.GetTimeout());
-
-    CopyHttpHeaders(client, command.GetHttpHeaders());
-
-    if (command.GetMethod() == Orthanc::HttpMethod_Post ||
-        command.GetMethod() == Orthanc::HttpMethod_Put)
-    {
-      client.SetBody(command.GetBody());
-    }
-
-    std::string answer;
-    Orthanc::HttpClient::HttpHeaders answerHeaders;
-    client.ApplyAndThrowException(answer, answerHeaders);
-
-    DecodeAnswer(answer, answerHeaders);
-
-    OrthancRestApiCommand::SuccessMessage message(command, answerHeaders, answer);
-    emitter.EmitMessage(receiver, message);
-  }
-
-
-  static void Execute(IMessageEmitter& emitter,
-                      const Orthanc::WebServiceParameters& orthanc,
-                      const IObserver& receiver,
-                      const GetOrthancImageCommand& command)
-  {
-    Orthanc::HttpClient client(orthanc, command.GetUri());
-    client.SetTimeout(command.GetTimeout());
-
-    CopyHttpHeaders(client, command.GetHttpHeaders());
-    
-    std::string answer;
-    Orthanc::HttpClient::HttpHeaders answerHeaders;
-    client.ApplyAndThrowException(answer, answerHeaders);
-
-    DecodeAnswer(answer, answerHeaders);
-
-    command.ProcessHttpAnswer(emitter, receiver, answer, answerHeaders);
-  }
-
-
-  static void Execute(IMessageEmitter& emitter,
-                      const Orthanc::WebServiceParameters& orthanc,
-                      const IObserver& receiver,
-                      const GetOrthancWebViewerJpegCommand& command)
-  {
-    Orthanc::HttpClient client(orthanc, command.GetUri());
-    client.SetTimeout(command.GetTimeout());
-
-    CopyHttpHeaders(client, command.GetHttpHeaders());
-
-    std::string answer;
-    Orthanc::HttpClient::HttpHeaders answerHeaders;
-    client.ApplyAndThrowException(answer, answerHeaders);
-
-    DecodeAnswer(answer, answerHeaders);
-
-    command.ProcessHttpAnswer(emitter, receiver, answer);
-  }
-
-
   void ThreadedOracle::Step()
   {
     std::auto_ptr<Orthanc::IDynamicObject>  object(queue_.Dequeue(100));
@@ -316,60 +160,23 @@
     {
       Item& item = dynamic_cast<Item&>(*object);
 
-      try
+      if (item.GetCommand().GetType() == IOracleCommand::Type_Sleep)
       {
-        switch (item.GetCommand().GetType())
+        SleepOracleCommand& command = dynamic_cast<SleepOracleCommand&>(item.GetCommand());
+          
+        std::auto_ptr<SleepOracleCommand> copy(new SleepOracleCommand(command.GetDelay()));
+          
+        if (command.HasPayload())
         {
-          case IOracleCommand::Type_Sleep:
-          {
-            SleepOracleCommand& command = dynamic_cast<SleepOracleCommand&>(item.GetCommand());
-
-            std::auto_ptr<SleepOracleCommand> copy(new SleepOracleCommand(command.GetDelay()));
-
-            if (command.HasPayload())
-            {
-              copy->SetPayload(command.ReleasePayload());
-            }
-
-            sleepingCommands_->Add(item.GetReceiver(), copy.release());
-
-            break;
-          }
-
-          case IOracleCommand::Type_Http:
-            Execute(emitter_, item.GetReceiver(), 
-                    dynamic_cast<const HttpCommand&>(item.GetCommand()));
-            break;
-
-          case IOracleCommand::Type_OrthancRestApi:
-            Execute(emitter_, orthanc_, item.GetReceiver(), 
-                    dynamic_cast<const OrthancRestApiCommand&>(item.GetCommand()));
-            break;
-
-          case IOracleCommand::Type_GetOrthancImage:
-            Execute(emitter_, orthanc_, item.GetReceiver(), 
-                    dynamic_cast<const GetOrthancImageCommand&>(item.GetCommand()));
-            break;
-
-          case IOracleCommand::Type_GetOrthancWebViewerJpeg:
-            Execute(emitter_, orthanc_, item.GetReceiver(), 
-                    dynamic_cast<const GetOrthancWebViewerJpegCommand&>(item.GetCommand()));
-            break;
-
-          default:
-            throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
+          copy->SetPayload(command.ReleasePayload());
         }
-      }
-      catch (Orthanc::OrthancException& e)
-      {
-        LOG(ERROR) << "Exception within the oracle: " << e.What();
-        emitter_.EmitMessage(item.GetReceiver(), OracleCommandExceptionMessage(item.GetCommand(), e));
+          
+        sleepingCommands_->Add(item.GetReceiver(), copy.release());
       }
-      catch (...)
+      else
       {
-        LOG(ERROR) << "Threaded exception within the oracle";
-        emitter_.EmitMessage(item.GetReceiver(), OracleCommandExceptionMessage
-                             (item.GetCommand(), Orthanc::ErrorCode_InternalError));
+        GenericOracleRunner runner(emitter_, orthanc_);
+        runner.Run(item.GetReceiver(), item.GetCommand());
       }
     }
   }
@@ -563,7 +370,7 @@
   }
 
 
-  void ThreadedOracle::Schedule(const IObserver& receiver,
+  void ThreadedOracle::Schedule(boost::shared_ptr<IObserver>& receiver,
                                 IOracleCommand* command)
   {
     queue_.Enqueue(new Item(receiver, command));
--- a/Framework/Oracle/ThreadedOracle.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Oracle/ThreadedOracle.h	Wed Oct 23 11:04:47 2019 +0200
@@ -29,10 +29,9 @@
 #  error This file can only compiled for native targets
 #endif
 
-#include "../Messages/IMessageEmitter.h"
 #include "IOracle.h"
+#include "GenericOracleRunner.h"
 
-#include <Core/WebServiceParameters.h>
 #include <Core/MultiThreading/SharedMessageQueue.h>
 
 
@@ -74,7 +73,6 @@
 
     virtual ~ThreadedOracle();
 
-    // The reference is not stored.
     void SetOrthancParameters(const Orthanc::WebServiceParameters& orthanc);
 
     void SetThreadsCount(unsigned int count);
@@ -88,7 +86,7 @@
       StopInternal();
     }
 
-    virtual void Schedule(const IObserver& receiver,
-                          IOracleCommand* command);
+    virtual void Schedule(boost::shared_ptr<IObserver>& receiver,
+                          IOracleCommand* command) ORTHANC_OVERRIDE;
   };
 }
--- a/Framework/Oracle/WebAssemblyOracle.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Oracle/WebAssemblyOracle.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -695,7 +695,7 @@
 
 
 
-  void WebAssemblyOracle::Schedule(const IObserver& receiver,
+  void WebAssemblyOracle::Schedule(boost::shared_ptr<IObserver>& receiver,
                                    IOracleCommand* command)
   {
     LOG(TRACE) << "WebAssemblyOracle::Schedule : receiver = "
--- a/Framework/Oracle/WebAssemblyOracle.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Oracle/WebAssemblyOracle.h	Wed Oct 23 11:04:47 2019 +0200
@@ -76,7 +76,7 @@
       orthancRoot_ = root;
     }
     
-    virtual void Schedule(const IObserver& receiver,
-                          IOracleCommand* command);
+    virtual void Schedule(boost::shared_ptr<IObserver>& receiver,
+                          IOracleCommand* command) ORTHANC_OVERRIDE;
   };
 }
--- a/Framework/Radiography/RadiographyAlphaLayer.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Radiography/RadiographyAlphaLayer.h	Wed Oct 23 11:04:47 2019 +0200
@@ -38,8 +38,8 @@
     float                                  foreground_;
 
   public:
-    RadiographyAlphaLayer(MessageBroker& broker, const RadiographyScene& scene) :
-      RadiographyLayer(broker, scene),
+    RadiographyAlphaLayer(const RadiographyScene& scene) :
+      RadiographyLayer(scene),
       useWindowing_(true),
       foreground_(0)
     {
--- a/Framework/Radiography/RadiographyDicomLayer.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Radiography/RadiographyDicomLayer.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -47,7 +47,8 @@
   }
 
 
-  RadiographyDicomLayer::RadiographyDicomLayer(MessageBroker& broker, const RadiographyScene& scene) : RadiographyLayer(broker, scene)
+  RadiographyDicomLayer::RadiographyDicomLayer(const RadiographyScene& scene) :
+    RadiographyLayer(scene)
   {
 
   }
--- a/Framework/Radiography/RadiographyDicomLayer.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Radiography/RadiographyDicomLayer.h	Wed Oct 23 11:04:47 2019 +0200
@@ -42,7 +42,7 @@
     void ApplyConverter();
 
   public:
-    RadiographyDicomLayer(MessageBroker& broker, const RadiographyScene& scene);
+    RadiographyDicomLayer(const RadiographyScene& scene);
 
     void SetInstance(const std::string& instanceId, unsigned int frame)
     {
--- a/Framework/Radiography/RadiographyLayer.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Radiography/RadiographyLayer.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -119,8 +119,7 @@
   }
 
 
-  RadiographyLayer::RadiographyLayer(MessageBroker& broker, const RadiographyScene& scene) :
-    IObservable(broker),
+  RadiographyLayer::RadiographyLayer(const RadiographyScene& scene) :
     index_(0),
     hasSize_(false),
     width_(0),
--- a/Framework/Radiography/RadiographyLayer.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Radiography/RadiographyLayer.h	Wed Oct 23 11:04:47 2019 +0200
@@ -248,7 +248,7 @@
                      double zoom);
 
   public:
-    RadiographyLayer(MessageBroker& broker, const RadiographyScene& scene);
+    RadiographyLayer(const RadiographyScene& scene);
 
     virtual ~RadiographyLayer()
     {
--- a/Framework/Radiography/RadiographyMaskLayer.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Radiography/RadiographyMaskLayer.h	Wed Oct 23 11:04:47 2019 +0200
@@ -40,9 +40,9 @@
 
     mutable std::auto_ptr<Orthanc::ImageAccessor>  mask_;
   public:
-    RadiographyMaskLayer(MessageBroker& broker, const RadiographyScene& scene, const RadiographyDicomLayer& dicomLayer,
+    RadiographyMaskLayer(const RadiographyScene& scene, const RadiographyDicomLayer& dicomLayer,
                          float foreground) :
-      RadiographyLayer(broker, scene),
+      RadiographyLayer(scene),
       dicomLayer_(dicomLayer),
       invalidated_(true),
       foreground_(foreground)
--- a/Framework/Radiography/RadiographyScene.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Radiography/RadiographyScene.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -142,7 +142,7 @@
 
     BroadcastMessage(GeometryChangedMessage(*this, *layer));
     BroadcastMessage(ContentChangedMessage(*this, *layer));
-    layer->RegisterObserverCallback(new Callable<RadiographyScene, RadiographyLayer::LayerEditedMessage>(*this, &RadiographyScene::OnLayerEdited));
+    Register<RadiographyLayer::LayerEditedMessage>(*layer, &RadiographyScene::OnLayerEdited);
 
     return *layer;
   }
@@ -162,9 +162,7 @@
     BroadcastMessage(RadiographyScene::LayerEditedMessage(*this, message.GetOrigin()));
   }
 
-  RadiographyScene::RadiographyScene(MessageBroker& broker) :
-    IObserver(broker),
-    IObservable(broker),
+  RadiographyScene::RadiographyScene() :
     countLayers_(0),
     hasWindowing_(false),
     windowingCenter_(0),  // Dummy initialization
@@ -284,7 +282,7 @@
                                                const std::string& utf8,
                                                RadiographyLayer::Geometry* geometry)
   {
-    std::auto_ptr<RadiographyTextLayer>  alpha(new RadiographyTextLayer(IObservable::GetBroker(), *this));
+    std::auto_ptr<RadiographyTextLayer>  alpha(new RadiographyTextLayer(*this));
     alpha->LoadText(font, utf8);
     if (geometry != NULL)
     {
@@ -328,7 +326,7 @@
                                                float foreground,
                                                RadiographyLayer::Geometry* geometry)
   {
-    std::auto_ptr<RadiographyMaskLayer>  mask(new RadiographyMaskLayer(IObservable::GetBroker(), *this, dicomLayer, foreground));
+    std::auto_ptr<RadiographyMaskLayer>  mask(new RadiographyMaskLayer(*this, dicomLayer, foreground));
     mask->SetCorners(corners);
     if (geometry != NULL)
     {
@@ -341,7 +339,7 @@
 
   RadiographyLayer& RadiographyScene::LoadAlphaBitmap(Orthanc::ImageAccessor* bitmap, RadiographyLayer::Geometry *geometry)
   {
-    std::auto_ptr<RadiographyAlphaLayer>  alpha(new RadiographyAlphaLayer(IObservable::GetBroker(), *this));
+    std::auto_ptr<RadiographyAlphaLayer>  alpha(new RadiographyAlphaLayer(*this));
     alpha->SetAlpha(bitmap);
     if (geometry != NULL)
     {
@@ -358,7 +356,7 @@
                                                      RadiographyPhotometricDisplayMode preferredPhotometricDisplayMode,
                                                      RadiographyLayer::Geometry* geometry)
   {
-    RadiographyDicomLayer& layer = dynamic_cast<RadiographyDicomLayer&>(RegisterLayer(new RadiographyDicomLayer(IObservable::GetBroker(), *this)));
+    RadiographyDicomLayer& layer = dynamic_cast<RadiographyDicomLayer&>(RegisterLayer(new RadiographyDicomLayer(*this)));
 
     layer.SetInstance(instance, frame);
 
@@ -380,7 +378,7 @@
                                                      bool httpCompression,
                                                      RadiographyLayer::Geometry* geometry)
   {
-    RadiographyDicomLayer& layer = dynamic_cast<RadiographyDicomLayer&>(RegisterLayer(new RadiographyDicomLayer(IObservable::GetBroker(), *this)));
+    RadiographyDicomLayer& layer = dynamic_cast<RadiographyDicomLayer&>(RegisterLayer(new RadiographyDicomLayer( *this)));
     layer.SetInstance(instance, frame);
 
     if (geometry != NULL)
@@ -395,7 +393,7 @@
       orthanc.GetBinaryAsync(
             uri, headers,
             new Callable<RadiographyScene, Deprecated::OrthancApiClient::BinaryResponseReadyMessage>
-            (*this, &RadiographyScene::OnTagsReceived), NULL,
+            (GetSharedObserver(), &RadiographyScene::OnTagsReceived), NULL,
             new Orthanc::SingleValueObject<size_t>(layer.GetIndex()));
     }
 
@@ -414,7 +412,7 @@
       orthanc.GetBinaryAsync(
             uri, headers,
             new Callable<RadiographyScene, Deprecated::OrthancApiClient::BinaryResponseReadyMessage>
-            (*this, &RadiographyScene::OnFrameReceived), NULL,
+            (GetSharedObserver(), &RadiographyScene::OnFrameReceived), NULL,
             new Orthanc::SingleValueObject<size_t>(layer.GetIndex()));
     }
 
@@ -424,7 +422,7 @@
 
   RadiographyLayer& RadiographyScene::LoadDicomWebFrame(Deprecated::IWebService& web)
   {
-    RadiographyLayer& layer = RegisterLayer(new RadiographyDicomLayer(IObservable::GetBroker(), *this));
+    RadiographyLayer& layer = RegisterLayer(new RadiographyDicomLayer(*this));
 
 
     return layer;
@@ -752,7 +750,7 @@
     orthanc.PostJsonAsyncExpectJson(
           "/tools/create-dicom", createDicomRequestContent,
           new Callable<RadiographyScene, Deprecated::OrthancApiClient::JsonResponseReadyMessage>
-          (*this, &RadiographyScene::OnDicomExported),
+          (GetSharedObserver(), &RadiographyScene::OnDicomExported),
           NULL, NULL);
 
   }
--- a/Framework/Radiography/RadiographyScene.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Radiography/RadiographyScene.h	Wed Oct 23 11:04:47 2019 +0200
@@ -22,6 +22,7 @@
 #pragma once
 
 #include "RadiographyLayer.h"
+#include "../Messages/ObserverBase.h"
 #include "../Deprecated/Toolbox/DicomFrameConverter.h"
 #include "../Deprecated/Toolbox/OrthancApiClient.h"
 #include "../StoneEnumerations.h"
@@ -33,8 +34,8 @@
   class RadiographyDicomLayer;
 
   class RadiographyScene :
-      public IObserver,
-      public IObservable
+    public ObserverBase<RadiographyScene>,
+    public IObservable
   {
   public:
     class GeometryChangedMessage : public OriginMessage<RadiographyScene>
@@ -159,7 +160,7 @@
 
     virtual void OnLayerEdited(const RadiographyLayer::LayerEditedMessage& message);
   public:
-    RadiographyScene(MessageBroker& broker);
+    RadiographyScene();
     
     virtual ~RadiographyScene();
 
--- a/Framework/Radiography/RadiographySceneReader.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Radiography/RadiographySceneReader.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -50,7 +50,7 @@
 
   RadiographyDicomLayer* RadiographySceneReader::LoadDicom(const std::string& instanceId, unsigned int frame, RadiographyLayer::Geometry* geometry)
   {
-    return dynamic_cast<RadiographyDicomLayer*>(&(scene_.LoadDicomFrame(orthancApiClient_, instanceId, frame, false, geometry)));
+    return dynamic_cast<RadiographyDicomLayer*>(&(scene_.LoadDicomFrame(*orthancApiClient_, instanceId, frame, false, geometry)));
   }
 
   void RadiographySceneBuilder::Read(const Json::Value& input)
@@ -161,7 +161,7 @@
       if (jsonLayer["type"].asString() == "dicom")
       {
         ReadLayerGeometry(geometry, jsonLayer);
-        dicomLayer = dynamic_cast<RadiographyDicomLayer*>(&(scene_.LoadDicomFrame(orthancApiClient_, jsonLayer["instanceId"].asString(), jsonLayer["frame"].asUInt(), false, &geometry)));
+        dicomLayer = dynamic_cast<RadiographyDicomLayer*>(&(scene_.LoadDicomFrame(*orthancApiClient_, jsonLayer["instanceId"].asString(), jsonLayer["frame"].asUInt(), false, &geometry)));
       }
       else if (jsonLayer["type"].asString() == "mask")
       {
--- a/Framework/Radiography/RadiographySceneReader.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Radiography/RadiographySceneReader.h	Wed Oct 23 11:04:47 2019 +0200
@@ -75,10 +75,12 @@
 
   class RadiographySceneReader : public RadiographySceneBuilder
   {
-    Deprecated::OrthancApiClient&             orthancApiClient_;
+  private:
+    boost::shared_ptr<Deprecated::OrthancApiClient>  orthancApiClient_;
 
   public:
-    RadiographySceneReader(RadiographyScene& scene, Deprecated::OrthancApiClient& orthancApiClient) :
+    RadiographySceneReader(RadiographyScene& scene,
+                           boost::shared_ptr<Deprecated::OrthancApiClient> orthancApiClient) :
       RadiographySceneBuilder(scene),
       orthancApiClient_(orthancApiClient)
     {
--- a/Framework/Radiography/RadiographyTextLayer.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Radiography/RadiographyTextLayer.h	Wed Oct 23 11:04:47 2019 +0200
@@ -34,8 +34,8 @@
     std::string                fontName_;
 
   public:
-    RadiographyTextLayer(MessageBroker& broker, const RadiographyScene& scene) :
-      RadiographyAlphaLayer(broker, scene)
+    RadiographyTextLayer(const RadiographyScene& scene) :
+      RadiographyAlphaLayer(scene)
     {
     }
 
--- a/Framework/Radiography/RadiographyWidget.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Radiography/RadiographyWidget.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -181,11 +181,9 @@
   }
 
 
-  RadiographyWidget::RadiographyWidget(MessageBroker& broker,
-                                       boost::shared_ptr<RadiographyScene> scene,
+  RadiographyWidget::RadiographyWidget(boost::shared_ptr<RadiographyScene> scene,
                                        const std::string& name) :
     WorldSceneWidget(name),
-    IObserver(broker),
     invert_(false),
     interpolation_(ImageInterpolation_Nearest),
     hasSelection_(false),
@@ -281,20 +279,10 @@
 
   void RadiographyWidget::SetScene(boost::shared_ptr<RadiographyScene> scene)
   {
-    if (scene_ != NULL)
-    {
-      scene_->Unregister(this);
-    }
-
     scene_ = scene;
 
-    scene_->RegisterObserverCallback(
-          new Callable<RadiographyWidget, RadiographyScene::GeometryChangedMessage>
-          (*this, &RadiographyWidget::OnGeometryChanged));
-
-    scene_->RegisterObserverCallback(
-          new Callable<RadiographyWidget, RadiographyScene::ContentChangedMessage>
-          (*this, &RadiographyWidget::OnContentChanged));
+    Register<RadiographyScene::GeometryChangedMessage>(*scene_, &RadiographyWidget::OnGeometryChanged);
+    Register<RadiographyScene::ContentChangedMessage>(*scene_, &RadiographyWidget::OnContentChanged);
 
     NotifyContentChanged();
 
--- a/Framework/Radiography/RadiographyWidget.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Radiography/RadiographyWidget.h	Wed Oct 23 11:04:47 2019 +0200
@@ -22,6 +22,7 @@
 #pragma once
 
 #include "../Deprecated/Widgets/WorldSceneWidget.h"
+#include "../Messages/ObserverBase.h"
 #include "RadiographyScene.h"
 
 
@@ -31,7 +32,7 @@
 
   class RadiographyWidget :
     public Deprecated::WorldSceneWidget,
-    public IObserver
+    public ObserverBase<RadiographyWidget>
   {
   private:
     boost::shared_ptr<RadiographyScene>    scene_;
@@ -60,8 +61,7 @@
     bool IsInvertedInternal() const;
 
   public:
-    RadiographyWidget(MessageBroker& broker,
-                      boost::shared_ptr<RadiographyScene> scene,  // TODO: check how we can avoid boost::shared_ptr here since we don't want them in the public API (app is keeping a boost::shared_ptr to this right now)
+    RadiographyWidget(boost::shared_ptr<RadiographyScene> scene,  // TODO: check how we can avoid boost::shared_ptr here since we don't want them in the public API (app is keeping a boost::shared_ptr to this right now)
                       const std::string& name);
 
     RadiographyScene& GetScene() const
--- a/Framework/Scene2DViewport/AngleMeasureTool.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Scene2DViewport/AngleMeasureTool.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -42,8 +42,8 @@
   // the params in the LayerHolder ctor specify the number of polyline and text
   // layers
   AngleMeasureTool::AngleMeasureTool(
-    MessageBroker& broker, boost::weak_ptr<ViewportController> controllerW)
-    : MeasureTool(broker, controllerW)
+    boost::weak_ptr<ViewportController> controllerW)
+    : MeasureTool(controllerW)
 #if ORTHANC_STONE_ENABLE_OUTLINED_TEXT == 1
     , layerHolder_(boost::make_shared<LayerHolder>(controllerW,1,5))
 #else
@@ -189,8 +189,9 @@
         boost::weak_ptr<ViewportController>          controllerW,
         const PointerEvent & e);
     */
+
     boost::shared_ptr<EditAngleMeasureTracker> editAngleMeasureTracker(
-      new EditAngleMeasureTracker(shared_from_this(), GetBroker(), GetController(), e));
+      new EditAngleMeasureTracker(shared_from_this(), GetController(), e));
     return editAngleMeasureTracker;
   }
 
--- a/Framework/Scene2DViewport/AngleMeasureTool.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Scene2DViewport/AngleMeasureTool.h	Wed Oct 23 11:04:47 2019 +0200
@@ -37,10 +37,10 @@
 
 namespace OrthancStone
 {
-  class AngleMeasureTool : public MeasureTool, public boost::enable_shared_from_this<AngleMeasureTool>
+  class AngleMeasureTool : public MeasureTool
   {
   public:
-    AngleMeasureTool(MessageBroker& broker, boost::weak_ptr<ViewportController> controllerW);
+    AngleMeasureTool(boost::weak_ptr<ViewportController> controllerW);
 
     ~AngleMeasureTool();
 
--- a/Framework/Scene2DViewport/CreateAngleMeasureCommand.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Scene2DViewport/CreateAngleMeasureCommand.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -26,12 +26,11 @@
 namespace OrthancStone
 {
   CreateAngleMeasureCommand::CreateAngleMeasureCommand(
-    MessageBroker& broker,
     boost::weak_ptr<ViewportController> controllerW,
     ScenePoint2D           point)
     : CreateMeasureCommand(controllerW)
     , measureTool_(
-      boost::make_shared<AngleMeasureTool>(boost::ref(broker), controllerW))
+      boost::make_shared<AngleMeasureTool>(controllerW))
   {
     GetController()->AddMeasureTool(measureTool_);
     measureTool_->SetSide1End(point);
--- a/Framework/Scene2DViewport/CreateAngleMeasureCommand.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Scene2DViewport/CreateAngleMeasureCommand.h	Wed Oct 23 11:04:47 2019 +0200
@@ -28,7 +28,6 @@
   public:
     /** Ctor sets end of side 1*/
     CreateAngleMeasureCommand(
-      MessageBroker& broker,
       boost::weak_ptr<ViewportController> controllerW,
       ScenePoint2D           point);
 
--- a/Framework/Scene2DViewport/CreateAngleMeasureTracker.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Scene2DViewport/CreateAngleMeasureTracker.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -26,7 +26,6 @@
 namespace OrthancStone
 {
   CreateAngleMeasureTracker::CreateAngleMeasureTracker(
-    MessageBroker&                  broker,
     boost::weak_ptr<ViewportController>          controllerW,
     const PointerEvent&             e)
     : CreateMeasureTracker(controllerW)
@@ -34,7 +33,6 @@
   {
     command_.reset(
       new CreateAngleMeasureCommand(
-        broker,
         controllerW,
         e.GetMainPosition().Apply(GetScene().GetCanvasToSceneTransform())));
   }
--- a/Framework/Scene2DViewport/CreateAngleMeasureTracker.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Scene2DViewport/CreateAngleMeasureTracker.h	Wed Oct 23 11:04:47 2019 +0200
@@ -38,7 +38,6 @@
     must be supplied, too
     */
     CreateAngleMeasureTracker(
-      MessageBroker&                  broker,
       boost::weak_ptr<ViewportController>          controllerW,
       const PointerEvent&             e);
 
--- a/Framework/Scene2DViewport/CreateLineMeasureCommand.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Scene2DViewport/CreateLineMeasureCommand.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -26,12 +26,11 @@
 namespace OrthancStone
 {
   CreateLineMeasureCommand::CreateLineMeasureCommand(
-    MessageBroker& broker,
     boost::weak_ptr<ViewportController> controllerW,
     ScenePoint2D           point)
     : CreateMeasureCommand(controllerW)
     , measureTool_(
-      boost::make_shared<LineMeasureTool>(boost::ref(broker), controllerW))
+      boost::make_shared<LineMeasureTool>(controllerW))
   {
     GetController()->AddMeasureTool(measureTool_);
     measureTool_->Set(point, point);
--- a/Framework/Scene2DViewport/CreateLineMeasureCommand.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Scene2DViewport/CreateLineMeasureCommand.h	Wed Oct 23 11:04:47 2019 +0200
@@ -27,7 +27,6 @@
   {
   public:
     CreateLineMeasureCommand(
-      MessageBroker& broker,
       boost::weak_ptr<ViewportController> controllerW,
       ScenePoint2D           point);
 
--- a/Framework/Scene2DViewport/CreateLineMeasureTracker.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Scene2DViewport/CreateLineMeasureTracker.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -26,14 +26,12 @@
 namespace OrthancStone
 {
   CreateLineMeasureTracker::CreateLineMeasureTracker(
-    MessageBroker&                  broker,
     boost::weak_ptr<ViewportController>          controllerW,
     const PointerEvent&             e)
     : CreateMeasureTracker(controllerW)
   {
     command_.reset(
       new CreateLineMeasureCommand(
-        broker,
         controllerW,
         e.GetMainPosition().Apply(GetScene().GetCanvasToSceneTransform())));
   }
--- a/Framework/Scene2DViewport/CreateLineMeasureTracker.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Scene2DViewport/CreateLineMeasureTracker.h	Wed Oct 23 11:04:47 2019 +0200
@@ -38,7 +38,6 @@
     must be supplied, too
     */
     CreateLineMeasureTracker(
-      MessageBroker&                  broker,
       boost::weak_ptr<ViewportController>          controllerW,
       const PointerEvent&             e);
 
--- a/Framework/Scene2DViewport/EditAngleMeasureCommand.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Scene2DViewport/EditAngleMeasureCommand.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -23,8 +23,7 @@
 namespace OrthancStone
 {
   EditAngleMeasureCommand::EditAngleMeasureCommand(
-    boost::shared_ptr<AngleMeasureTool>  measureTool,
-    MessageBroker& broker,
+    boost::shared_ptr<MeasureTool>  measureTool,
     boost::weak_ptr<ViewportController> controllerW)
     : EditMeasureCommand(measureTool, controllerW)
     , measureTool_(measureTool)
@@ -33,21 +32,21 @@
 
   void EditAngleMeasureCommand::SetCenter(ScenePoint2D scenePos)
   {
-    measureTool_->SetCenter(scenePos);
+    dynamic_cast<AngleMeasureTool&>(*measureTool_).SetCenter(scenePos);
     mementoModified_ = measureTool_->GetMemento();
   }
 
 
   void EditAngleMeasureCommand::SetSide1End(ScenePoint2D scenePos)
   {
-    measureTool_->SetSide1End(scenePos);
+    dynamic_cast<AngleMeasureTool&>(*measureTool_).SetSide1End(scenePos);
     mementoModified_ = measureTool_->GetMemento();
   }
 
 
   void EditAngleMeasureCommand::SetSide2End(ScenePoint2D scenePos)
   {
-    measureTool_->SetSide2End(scenePos);
+    dynamic_cast<AngleMeasureTool&>(*measureTool_).SetSide2End(scenePos);
     mementoModified_ = measureTool_->GetMemento();
   }
 }
--- a/Framework/Scene2DViewport/EditAngleMeasureCommand.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Scene2DViewport/EditAngleMeasureCommand.h	Wed Oct 23 11:04:47 2019 +0200
@@ -28,8 +28,7 @@
   public:
     /** Ctor sets end of side 1*/
     EditAngleMeasureCommand(
-      boost::shared_ptr<AngleMeasureTool>  measureTool,
-      MessageBroker& broker,
+      boost::shared_ptr<MeasureTool>  measureTool,
       boost::weak_ptr<ViewportController> controllerW);
 
     /** This method sets center*/
@@ -46,6 +45,6 @@
     {
       return measureTool_;
     }
-    boost::shared_ptr<AngleMeasureTool> measureTool_;
+    boost::shared_ptr<MeasureTool> measureTool_;
   };
 }
--- a/Framework/Scene2DViewport/EditAngleMeasureTracker.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Scene2DViewport/EditAngleMeasureTracker.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -26,8 +26,7 @@
 namespace OrthancStone
 {
   EditAngleMeasureTracker::EditAngleMeasureTracker(
-    boost::shared_ptr<AngleMeasureTool>  measureTool,
-    MessageBroker& broker,
+    boost::shared_ptr<MeasureTool>  measureTool,
     boost::weak_ptr<ViewportController> controllerW,
     const PointerEvent& e)
     : EditMeasureTracker(controllerW, e)
@@ -35,9 +34,9 @@
     ScenePoint2D scenePos = e.GetMainPosition().Apply(
       GetScene().GetCanvasToSceneTransform());
 
-    modifiedZone_ = measureTool->AngleHitTest(scenePos);
+    modifiedZone_ = dynamic_cast<AngleMeasureTool&>(*measureTool).AngleHitTest(scenePos);
 
-    command_.reset(new EditAngleMeasureCommand(measureTool, broker, controllerW));
+    command_.reset(new EditAngleMeasureCommand(measureTool, controllerW));
   }
 
   EditAngleMeasureTracker::~EditAngleMeasureTracker()
--- a/Framework/Scene2DViewport/EditAngleMeasureTracker.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Scene2DViewport/EditAngleMeasureTracker.h	Wed Oct 23 11:04:47 2019 +0200
@@ -37,8 +37,7 @@
     must be supplied, too
     */
     EditAngleMeasureTracker(
-      boost::shared_ptr<AngleMeasureTool>  measureTool,
-      MessageBroker& broker,
+      boost::shared_ptr<MeasureTool>  measureTool,
       boost::weak_ptr<ViewportController> controllerW,
       const PointerEvent& e);
 
--- a/Framework/Scene2DViewport/EditLineMeasureCommand.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Scene2DViewport/EditLineMeasureCommand.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -23,8 +23,7 @@
 namespace OrthancStone
 {
   EditLineMeasureCommand::EditLineMeasureCommand(
-    boost::shared_ptr<LineMeasureTool>  measureTool,
-    MessageBroker& broker,
+    boost::shared_ptr<MeasureTool>  measureTool,
     boost::weak_ptr<ViewportController> controllerW)
     : EditMeasureCommand(measureTool, controllerW)
     , measureTool_(measureTool)
@@ -34,14 +33,14 @@
 
   void EditLineMeasureCommand::SetStart(ScenePoint2D scenePos)
   {
-    measureTool_->SetStart(scenePos);
+    dynamic_cast<LineMeasureTool&>(*measureTool_).SetStart(scenePos);
     mementoModified_ = measureTool_->GetMemento();
   }
 
 
   void EditLineMeasureCommand::SetEnd(ScenePoint2D scenePos)
   {
-    measureTool_->SetEnd(scenePos);
+    dynamic_cast<LineMeasureTool&>(*measureTool_).SetEnd(scenePos);
     mementoModified_ = measureTool_->GetMemento();
   }
 }
--- a/Framework/Scene2DViewport/EditLineMeasureCommand.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Scene2DViewport/EditLineMeasureCommand.h	Wed Oct 23 11:04:47 2019 +0200
@@ -27,8 +27,7 @@
   {
   public:
     EditLineMeasureCommand(
-      boost::shared_ptr<LineMeasureTool>  measureTool,
-      MessageBroker& broker,
+      boost::shared_ptr<MeasureTool>  measureTool,
       boost::weak_ptr<ViewportController> controllerW);
 
     void SetStart(ScenePoint2D scenePos);
@@ -39,7 +38,6 @@
     {
       return measureTool_;
     }
-    boost::shared_ptr<LineMeasureTool> measureTool_;
+    boost::shared_ptr<MeasureTool> measureTool_;
   };
 }
-
--- a/Framework/Scene2DViewport/EditLineMeasureTracker.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Scene2DViewport/EditLineMeasureTracker.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -27,8 +27,7 @@
 namespace OrthancStone
 {
   EditLineMeasureTracker::EditLineMeasureTracker(
-    boost::shared_ptr<LineMeasureTool>  measureTool,
-    MessageBroker& broker,
+    boost::shared_ptr<MeasureTool>  measureTool,
     boost::weak_ptr<ViewportController> controllerW,
     const PointerEvent& e) 
     : EditMeasureTracker(controllerW, e)
@@ -36,13 +35,9 @@
     ScenePoint2D scenePos = e.GetMainPosition().Apply(
       GetScene().GetCanvasToSceneTransform());
 
-    modifiedZone_ = measureTool->LineHitTest(scenePos);
+    modifiedZone_ = dynamic_cast<LineMeasureTool&>(*measureTool).LineHitTest(scenePos);
 
-    command_.reset(
-      new EditLineMeasureCommand(
-        measureTool,
-        broker,
-        controllerW));
+    command_.reset(new EditLineMeasureCommand(measureTool, controllerW));
   }
 
   EditLineMeasureTracker::~EditLineMeasureTracker()
--- a/Framework/Scene2DViewport/EditLineMeasureTracker.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Scene2DViewport/EditLineMeasureTracker.h	Wed Oct 23 11:04:47 2019 +0200
@@ -37,8 +37,7 @@
     must be supplied, too
     */
     EditLineMeasureTracker(
-      boost::shared_ptr<LineMeasureTool>  measureTool,
-      MessageBroker&                      broker,
+      boost::shared_ptr<MeasureTool>  measureTool,
       boost::weak_ptr<ViewportController> controllerW,
       const PointerEvent&                 e);
 
--- a/Framework/Scene2DViewport/LineMeasureTool.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Scene2DViewport/LineMeasureTool.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -32,8 +32,8 @@
 {
 
   LineMeasureTool::LineMeasureTool(
-    MessageBroker& broker, boost::weak_ptr<ViewportController> controllerW)
-    : MeasureTool(broker, controllerW)
+    boost::weak_ptr<ViewportController> controllerW)
+    : MeasureTool(controllerW)
 #if ORTHANC_STONE_ENABLE_OUTLINED_TEXT == 1
     , layerHolder_(boost::make_shared<LayerHolder>(controllerW, 1, 5))
 #else
@@ -148,7 +148,7 @@
         const PointerEvent & e);
     */
     boost::shared_ptr<EditLineMeasureTracker> editLineMeasureTracker(
-      new EditLineMeasureTracker(shared_from_this(), GetBroker(), GetController(), e));
+      new EditLineMeasureTracker(shared_from_this(), GetController(), e));
     return editLineMeasureTracker;
   }
 
--- a/Framework/Scene2DViewport/LineMeasureTool.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Scene2DViewport/LineMeasureTool.h	Wed Oct 23 11:04:47 2019 +0200
@@ -35,10 +35,10 @@
 
 namespace OrthancStone
 {
-  class LineMeasureTool : public MeasureTool, public boost::enable_shared_from_this<LineMeasureTool>
+  class LineMeasureTool : public MeasureTool
   {
   public:
-    LineMeasureTool(MessageBroker& broker, boost::weak_ptr<ViewportController> controllerW);
+    LineMeasureTool(boost::weak_ptr<ViewportController> controllerW);
 
     ~LineMeasureTool();
 
--- a/Framework/Scene2DViewport/MeasureTool.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Scene2DViewport/MeasureTool.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -28,14 +28,6 @@
 
 namespace OrthancStone
 {
-  MeasureTool::~MeasureTool()
-  {
-    // if the controller is dead, let's not bother.
-    boost::shared_ptr<ViewportController> controller = controllerW_.lock();
-    if (controller)
-      controller->Unregister(this);
-  }
-
   void MeasureTool::Enable()
   {
     enabled_ = true;
@@ -79,15 +71,13 @@
 #endif
   }
 
-  MeasureTool::MeasureTool(MessageBroker& broker,
+  MeasureTool::MeasureTool(
     boost::weak_ptr<ViewportController> controllerW)
-    : IObserver(broker)
-    , controllerW_(controllerW)
+    : controllerW_(controllerW)
     , enabled_(true)
   {
-    GetController()->RegisterObserverCallback(
-      new Callable<MeasureTool, ViewportController::SceneTransformChanged>
-      (*this, &MeasureTool::OnSceneTransformChanged));
+    // TODO => Move this out of constructor
+    Register<ViewportController::SceneTransformChanged>(*GetController(), &MeasureTool::OnSceneTransformChanged);
   }
 
 
--- a/Framework/Scene2DViewport/MeasureTool.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Scene2DViewport/MeasureTool.h	Wed Oct 23 11:04:47 2019 +0200
@@ -20,6 +20,7 @@
 
 #pragma once
 
+#include "../Messages/ObserverBase.h"
 #include "../Scene2D/PolylineSceneLayer.h"
 #include "../Scene2D/Scene2D.h"
 #include "../Scene2D/ScenePoint2D.h"
@@ -27,7 +28,6 @@
 #include "../Scene2DViewport/PredeclaredTypes.h"
 #include "../Scene2DViewport/ViewportController.h"
 
-#include <boost/shared_ptr.hpp>
 #include <boost/weak_ptr.hpp>
 
 #include <vector>
@@ -38,10 +38,12 @@
   class IFlexiblePointerTracker;
   class MeasureToolMemento;
 
-  class MeasureTool : public IObserver
+  class MeasureTool : public ObserverBase<MeasureTool>
   {
   public:
-    virtual ~MeasureTool();
+    virtual ~MeasureTool()
+    {
+    }
 
     /**
     Enabled tools are rendered in the scene.
@@ -111,7 +113,7 @@
     virtual std::string GetDescription() = 0;
 
   protected:
-    MeasureTool(MessageBroker& broker, boost::weak_ptr<ViewportController> controllerW);
+    MeasureTool(boost::weak_ptr<ViewportController> controllerW);
 
     /**
     The measuring tool may exist in a standalone fashion, without any available
--- a/Framework/Scene2DViewport/ViewportController.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Scene2DViewport/ViewportController.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -30,10 +30,8 @@
 namespace OrthancStone
 {
   ViewportController::ViewportController(boost::weak_ptr<UndoStack> undoStackW,
-                                         MessageBroker& broker,
                                          IViewport& viewport)
-    : IObservable(broker)
-    , undoStackW_(undoStackW)
+    : undoStackW_(undoStackW)
     , canvasToSceneFactor_(0.0)
     , viewport_(viewport)
   {
--- a/Framework/Scene2DViewport/ViewportController.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Scene2DViewport/ViewportController.h	Wed Oct 23 11:04:47 2019 +0200
@@ -81,7 +81,6 @@
       SceneTransformChanged, ViewportController);
 
     ViewportController(boost::weak_ptr<UndoStack> undoStackW,
-                       MessageBroker& broker,
                        IViewport& viewport);
 
 
--- a/Framework/Toolbox/GenericToolbox.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Toolbox/GenericToolbox.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -29,7 +29,7 @@
   {
     bool GetRgbaValuesFromString(uint8_t& red, uint8_t& green, uint8_t& blue, uint8_t& alpha, const char* text)
     {
-      boost::regex pattern(R"bgo(\s*rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)\s*)bgo");
+      boost::regex pattern("\\s*rgb\\s*\\(\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*\\)\\s*");
 
       boost::cmatch what;
 
@@ -68,7 +68,7 @@
     }
     bool GetRgbValuesFromString(uint8_t& red, uint8_t& green, uint8_t& blue, const char* text)
     {
-      boost::regex pattern(R"bgo(\s*rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)\s*)bgo");
+      boost::regex pattern("\\s*rgb\\s*\\(\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*\\)\\s*");
 
       boost::cmatch what;
 
--- a/Framework/Toolbox/GenericToolbox.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Framework/Toolbox/GenericToolbox.h	Wed Oct 23 11:04:47 2019 +0200
@@ -116,7 +116,7 @@
       if (*p == '.')
       {
         double f = 0.0;
-        int n = 1;
+        size_t n = 1;
         ++p;
         while (*p >= '0' && *p <= '9' && n < FRAC_FACTORS_LEN)
         {
--- a/Platforms/Generic/DelayedCallCommand.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Platforms/Generic/DelayedCallCommand.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -26,13 +26,11 @@
 
 namespace Deprecated
 {
-  DelayedCallCommand::DelayedCallCommand(OrthancStone::MessageBroker& broker,
-                                         OrthancStone::MessageHandler<IDelayedCallExecutor::TimeoutMessage>* callback,  // takes ownership
+  DelayedCallCommand::DelayedCallCommand(OrthancStone::MessageHandler<IDelayedCallExecutor::TimeoutMessage>* callback,  // takes ownership
                                          unsigned int timeoutInMs,
                                          Orthanc::IDynamicObject* payload /* takes ownership */,
                                          OrthancStone::NativeStoneApplicationContext& context
                                          ) :
-    IObservable(broker),
     callback_(callback),
     payload_(payload),
     context_(context),
--- a/Platforms/Generic/DelayedCallCommand.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Platforms/Generic/DelayedCallCommand.h	Wed Oct 23 11:04:47 2019 +0200
@@ -42,8 +42,7 @@
     unsigned int                            timeoutInMs_;
 
   public:
-    DelayedCallCommand(OrthancStone::MessageBroker& broker,
-                       OrthancStone::MessageHandler<IDelayedCallExecutor::TimeoutMessage>* callback,  // takes ownership
+    DelayedCallCommand(OrthancStone::MessageHandler<IDelayedCallExecutor::TimeoutMessage>* callback,  // takes ownership
                        unsigned int timeoutInMs,
                        Orthanc::IDynamicObject* payload /* takes ownership */,
                        OrthancStone::NativeStoneApplicationContext& context
--- a/Platforms/Generic/OracleDelayedCallExecutor.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Platforms/Generic/OracleDelayedCallExecutor.h	Wed Oct 23 11:04:47 2019 +0200
@@ -36,10 +36,8 @@
     OrthancStone::NativeStoneApplicationContext& context_;
 
   public:
-    OracleDelayedCallExecutor(OrthancStone::MessageBroker& broker,
-                              Oracle& oracle,
+    OracleDelayedCallExecutor(Oracle& oracle,
                               OrthancStone::NativeStoneApplicationContext& context) :
-      IDelayedCallExecutor(broker),
       oracle_(oracle),
       context_(context)
     {
@@ -48,7 +46,7 @@
     virtual void Schedule(OrthancStone::MessageHandler<IDelayedCallExecutor::TimeoutMessage>* callback,
                           unsigned int timeoutInMs = 1000)
     {
-      oracle_.Submit(new DelayedCallCommand(broker_, callback, timeoutInMs, NULL, context_));
+      oracle_.Submit(new DelayedCallCommand(callback, timeoutInMs, NULL, context_));
     }
   };
 }
--- a/Platforms/Generic/OracleWebService.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Platforms/Generic/OracleWebService.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -35,13 +35,11 @@
     OrthancStone::NativeStoneApplicationContext&                                          context_;
 
   public:
-    WebServiceCachedGetCommand(OrthancStone::MessageBroker& broker,
-                               OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
+    WebServiceCachedGetCommand(OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
                                boost::shared_ptr<BaseWebService::CachedHttpRequestSuccessMessage> cachedMessage,
                                Orthanc::IDynamicObject* payload /* takes ownership */,
                                OrthancStone::NativeStoneApplicationContext& context
                                ) :
-      IObservable(broker),
       successCallback_(successCallback),
       payload_(payload),
       cachedMessage_(cachedMessage),
@@ -75,7 +73,7 @@
                                                 Orthanc::IDynamicObject* payload, // takes ownership
                                                 OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback)
   {
-    oracle_.Submit(new WebServiceCachedGetCommand(GetBroker(), successCallback, cachedMessage, payload, context_));
+    oracle_.Submit(new WebServiceCachedGetCommand(successCallback, cachedMessage, payload, context_));
   }
 
 
--- a/Platforms/Generic/OracleWebService.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Platforms/Generic/OracleWebService.h	Wed Oct 23 11:04:47 2019 +0200
@@ -43,11 +43,9 @@
     class WebServiceCachedGetCommand;
 
   public:
-    OracleWebService(OrthancStone::MessageBroker& broker,
-                     Oracle& oracle,
+    OracleWebService(Oracle& oracle,
                      const Orthanc::WebServiceParameters& parameters,
                      OrthancStone::NativeStoneApplicationContext& context) :
-      BaseWebService(broker),
       oracle_(oracle),
       context_(context),
       parameters_(parameters)
@@ -62,7 +60,7 @@
                            OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL, // takes ownership
                            unsigned int timeoutInSeconds = 60)
     {
-      oracle_.Submit(new WebServicePostCommand(GetBroker(), successCallback, failureCallback, parameters_, uri, headers, timeoutInSeconds, body, payload, context_));
+      oracle_.Submit(new WebServicePostCommand(successCallback, failureCallback, parameters_, uri, headers, timeoutInSeconds, body, payload, context_));
     }
 
     virtual void DeleteAsync(const std::string& uri,
@@ -72,7 +70,7 @@
                              OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,
                              unsigned int timeoutInSeconds = 60)
     {
-      oracle_.Submit(new WebServiceDeleteCommand(GetBroker(), successCallback, failureCallback, parameters_, uri, headers, timeoutInSeconds, payload, context_));
+      oracle_.Submit(new WebServiceDeleteCommand(successCallback, failureCallback, parameters_, uri, headers, timeoutInSeconds, payload, context_));
     }
 
   protected:
@@ -83,7 +81,7 @@
                                   OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback = NULL,// takes ownership
                                   unsigned int timeoutInSeconds = 60)
     {
-      oracle_.Submit(new WebServiceGetCommand(GetBroker(), successCallback, failureCallback, parameters_, uri, headers, timeoutInSeconds, payload, context_));
+      oracle_.Submit(new WebServiceGetCommand(successCallback, failureCallback, parameters_, uri, headers, timeoutInSeconds, payload, context_));
     }
 
     virtual void NotifyHttpSuccessLater(boost::shared_ptr<BaseWebService::CachedHttpRequestSuccessMessage> cachedHttpMessage,
--- a/Platforms/Generic/WebServiceCommandBase.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Platforms/Generic/WebServiceCommandBase.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -25,8 +25,7 @@
 
 namespace Deprecated
 {
-  WebServiceCommandBase::WebServiceCommandBase(OrthancStone::MessageBroker& broker,
-                                               OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
+  WebServiceCommandBase::WebServiceCommandBase(OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,
                                                OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
                                                const Orthanc::WebServiceParameters& parameters,
                                                const std::string& url,
@@ -34,7 +33,6 @@
                                                unsigned int timeoutInSeconds,
                                                Orthanc::IDynamicObject* payload /* takes ownership */,
                                                OrthancStone::NativeStoneApplicationContext& context) :
-    IObservable(broker),
     successCallback_(successCallback),
     failureCallback_(failureCallback),
     parameters_(parameters),
--- a/Platforms/Generic/WebServiceCommandBase.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Platforms/Generic/WebServiceCommandBase.h	Wed Oct 23 11:04:47 2019 +0200
@@ -51,8 +51,7 @@
     unsigned int                            timeoutInSeconds_;
 
   public:
-    WebServiceCommandBase(OrthancStone::MessageBroker& broker,
-                          OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
+    WebServiceCommandBase(OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
                           OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,  // takes ownership
                           const Orthanc::WebServiceParameters& parameters,
                           const std::string& url,
--- a/Platforms/Generic/WebServiceDeleteCommand.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Platforms/Generic/WebServiceDeleteCommand.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -25,8 +25,7 @@
 
 namespace Deprecated
 {
-  WebServiceDeleteCommand::WebServiceDeleteCommand(OrthancStone::MessageBroker& broker,
-                                                   OrthancStone::MessageHandler<Deprecated::IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
+  WebServiceDeleteCommand::WebServiceDeleteCommand(OrthancStone::MessageHandler<Deprecated::IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
                                                    OrthancStone::MessageHandler<Deprecated::IWebService::HttpRequestErrorMessage>* failureCallback,  // takes ownership
                                                    const Orthanc::WebServiceParameters& parameters,
                                                    const std::string& url,
@@ -34,7 +33,7 @@
                                                    unsigned int timeoutInSeconds,
                                                    Orthanc::IDynamicObject* payload /* takes ownership */,
                                                    OrthancStone::NativeStoneApplicationContext& context) :
-    WebServiceCommandBase(broker, successCallback, failureCallback, parameters, url, headers, timeoutInSeconds, payload, context)
+    WebServiceCommandBase(successCallback, failureCallback, parameters, url, headers, timeoutInSeconds, payload, context)
   {
   }
 
--- a/Platforms/Generic/WebServiceDeleteCommand.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Platforms/Generic/WebServiceDeleteCommand.h	Wed Oct 23 11:04:47 2019 +0200
@@ -28,8 +28,7 @@
   class WebServiceDeleteCommand : public WebServiceCommandBase
   {
   public:
-    WebServiceDeleteCommand(OrthancStone::MessageBroker& broker,
-                            OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
+    WebServiceDeleteCommand(OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
                             OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,  // takes ownership
                             const Orthanc::WebServiceParameters& parameters,
                             const std::string& url,
--- a/Platforms/Generic/WebServiceGetCommand.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Platforms/Generic/WebServiceGetCommand.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -25,9 +25,7 @@
 
 namespace Deprecated
 {
-
-  WebServiceGetCommand::WebServiceGetCommand(OrthancStone::MessageBroker& broker,
-                                             OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
+  WebServiceGetCommand::WebServiceGetCommand(OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
                                              OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,  // takes ownership
                                              const Orthanc::WebServiceParameters& parameters,
                                              const std::string& url,
@@ -35,7 +33,7 @@
                                              unsigned int timeoutInSeconds,
                                              Orthanc::IDynamicObject* payload /* takes ownership */,
                                              OrthancStone::NativeStoneApplicationContext& context) :
-    WebServiceCommandBase(broker, successCallback, failureCallback, parameters, url, headers, timeoutInSeconds, payload, context)
+    WebServiceCommandBase(successCallback, failureCallback, parameters, url, headers, timeoutInSeconds, payload, context)
   {
   }
 
--- a/Platforms/Generic/WebServiceGetCommand.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Platforms/Generic/WebServiceGetCommand.h	Wed Oct 23 11:04:47 2019 +0200
@@ -28,8 +28,7 @@
   class WebServiceGetCommand : public WebServiceCommandBase
   {
   public:
-    WebServiceGetCommand(OrthancStone::MessageBroker& broker,
-                         OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
+    WebServiceGetCommand(OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
                          OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,  // takes ownership
                          const Orthanc::WebServiceParameters& parameters,
                          const std::string& url,
--- a/Platforms/Generic/WebServicePostCommand.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/Platforms/Generic/WebServicePostCommand.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -25,8 +25,7 @@
 
 namespace Deprecated
 {
-  WebServicePostCommand::WebServicePostCommand(OrthancStone::MessageBroker& broker,
-                                               OrthancStone::MessageHandler<Deprecated::IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
+  WebServicePostCommand::WebServicePostCommand(OrthancStone::MessageHandler<Deprecated::IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
                                                OrthancStone::MessageHandler<Deprecated::IWebService::HttpRequestErrorMessage>* failureCallback,  // takes ownership
                                                const Orthanc::WebServiceParameters& parameters,
                                                const std::string& url,
@@ -35,7 +34,7 @@
                                                const std::string& body,
                                                Orthanc::IDynamicObject* payload /* takes ownership */,
                                                OrthancStone::NativeStoneApplicationContext& context) :
-    WebServiceCommandBase(broker, successCallback, failureCallback, parameters, url, headers, timeoutInSeconds, payload, context),
+    WebServiceCommandBase(successCallback, failureCallback, parameters, url, headers, timeoutInSeconds, payload, context),
     body_(body)
   {
   }
--- a/Platforms/Generic/WebServicePostCommand.h	Tue Oct 22 17:51:25 2019 +0200
+++ b/Platforms/Generic/WebServicePostCommand.h	Wed Oct 23 11:04:47 2019 +0200
@@ -31,8 +31,7 @@
     std::string  body_;
 
   public:
-    WebServicePostCommand(OrthancStone::MessageBroker& broker,
-                          OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
+    WebServicePostCommand(OrthancStone::MessageHandler<IWebService::HttpRequestSuccessMessage>* successCallback,  // takes ownership
                           OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,  // takes ownership
                           const Orthanc::WebServiceParameters& parameters,
                           const std::string& url,
--- a/Resources/CMake/OrthancStoneConfiguration.cmake	Tue Oct 22 17:51:25 2019 +0200
+++ b/Resources/CMake/OrthancStoneConfiguration.cmake	Wed Oct 23 11:04:47 2019 +0200
@@ -401,8 +401,10 @@
 
 if (ENABLE_THREADS)
   list(APPEND ORTHANC_STONE_SOURCES
+    ${ORTHANC_STONE_ROOT}/Framework/Messages/LockingEmitter.cpp
     ${ORTHANC_STONE_ROOT}/Framework/Messages/LockingEmitter.h
     ${ORTHANC_STONE_ROOT}/Framework/Oracle/ThreadedOracle.cpp
+    ${ORTHANC_STONE_ROOT}/Framework/Oracle/GenericOracleRunner.cpp
     )
 endif()
 
@@ -452,10 +454,7 @@
   ${ORTHANC_STONE_ROOT}/Framework/Messages/ICallable.h
   ${ORTHANC_STONE_ROOT}/Framework/Messages/IMessage.h
   ${ORTHANC_STONE_ROOT}/Framework/Messages/IObservable.cpp
-  ${ORTHANC_STONE_ROOT}/Framework/Messages/IObserver.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Messages/IObserver.h
-  ${ORTHANC_STONE_ROOT}/Framework/Messages/MessageBroker.h
-  ${ORTHANC_STONE_ROOT}/Framework/Messages/MessageForwarder.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Oracle/GetOrthancImageCommand.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Oracle/GetOrthancWebViewerJpegCommand.cpp
   ${ORTHANC_STONE_ROOT}/Framework/Oracle/OracleCommandWithPayload.cpp
--- a/UnitTestsSources/GenericToolboxTests.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/UnitTestsSources/GenericToolboxTests.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -3762,7 +3762,7 @@
   for (double b = DBL_EPSILON; b < DBL_MAX && i < COUNT; ++i, b *= FACTOR)
   {
     char txt[1024];
-    sprintf_s(txt, "%.17f", b);
+    snprintf(txt, sizeof(txt) - 1, "%.17f", b);
     double r = 0.0;
     bool ok = StringToDouble(r, txt);
     
@@ -3802,7 +3802,7 @@
   for (double b = -1.0*DBL_EPSILON; b < DBL_MAX && i < COUNT; ++i, b *= FACTOR)
   {
     char txt[1024];
-    sprintf_s(txt, "%.17f", b);
+    snprintf(txt, sizeof(txt) - 1, "%.17f", b);
     double r = 0.0;
     bool ok = StringToDouble(r, txt);
 
@@ -3843,9 +3843,9 @@
     int64_t bi = static_cast<int64_t>(b);
     char txt[1024];
 #if (defined __clang__) || (defined __GNUC__) || ( (defined _MSC_VER) && (_MSC_VER > 1800) )
-    sprintf_s(txt, "%lld", bi);
+    snprintf(txt, sizeof(txt) - 1, "%ld", bi);
 #elif (defined _MSC_VER)
-    sprintf_s(txt, "%I64d", bi);
+    snprintf(txt, sizeof(txt) - 1, "%I64d", bi);
 #else
 #error Please adjust for your platform
 #endif
--- a/UnitTestsSources/TestMessageBroker.cpp	Tue Oct 22 17:51:25 2019 +0200
+++ b/UnitTestsSources/TestMessageBroker.cpp	Wed Oct 23 11:04:47 2019 +0200
@@ -21,10 +21,8 @@
 
 #include "gtest/gtest.h"
 
-#include "../Framework/Messages/MessageBroker.h"
-#include "../Framework/Messages/IObservable.h"
-#include "../Framework/Messages/IObserver.h"
-#include "../Framework/Messages/MessageForwarder.h"
+#include "Framework/Messages/IObservable.h"
+#include "Framework/Messages/ObserverBase.h"
 
 
 int testCounter = 0;
@@ -47,51 +45,26 @@
       {
       }
     };
-
-    MyObservable(MessageBroker& broker) :
-      IObservable(broker)
-    {
-    }
   };
 
-  class MyObserver : public IObserver
+  class MyObserver : public ObserverBase<MyObserver>
   {
   public:
-    MyObserver(MessageBroker& broker)
-      : IObserver(broker)
-    {}
-
     void HandleCompletedMessage(const MyObservable::MyCustomMessage& message)
     {
       testCounter += message.payload_;
     }
-
-  };
-
-
-  class MyIntermediate : public IObserver, public IObservable
-  {
-    IObservable& observedObject_;
-  public:
-    MyIntermediate(MessageBroker& broker, IObservable& observedObject)
-      : IObserver(broker),
-        IObservable(broker),
-        observedObject_(observedObject)
-    {
-      observedObject_.RegisterObserverCallback(new MessageForwarder<MyObservable::MyCustomMessage>(broker, *this));
-    }
   };
 }
 
 
 TEST(MessageBroker, TestPermanentConnectionSimpleUseCase)
 {
-  MessageBroker broker;
-  MyObservable  observable(broker);
-  MyObserver    observer(broker);
+  MyObservable  observable;
+  boost::shared_ptr<MyObserver>  observer(new MyObserver);
 
   // create a permanent connection between an observable and an observer
-  observable.RegisterObserverCallback(new Callable<MyObserver, MyObservable::MyCustomMessage>(observer, &MyObserver::HandleCompletedMessage));
+  observer->Register<MyObservable::MyCustomMessage>(observable, &MyObserver::HandleCompletedMessage);
 
   testCounter = 0;
   observable.BroadcastMessage(MyObservable::MyCustomMessage(12));
@@ -103,155 +76,29 @@
   ASSERT_EQ(20, testCounter);
 
   // Unregister the observer; make sure it's not called anymore
-  observable.Unregister(&observer);
+  observer.reset();
   testCounter = 0;
   observable.BroadcastMessage(MyObservable::MyCustomMessage(20));
   ASSERT_EQ(0, testCounter);
 }
 
-TEST(MessageBroker, TestMessageForwarderSimpleUseCase)
-{
-  MessageBroker broker;
-  MyObservable  observable(broker);
-  MyIntermediate intermediate(broker, observable);
-  MyObserver    observer(broker);
-
-  // let the observer observers the intermediate that is actually forwarding the messages from the observable
-  intermediate.RegisterObserverCallback(new Callable<MyObserver, MyObservable::MyCustomMessage>(observer, &MyObserver::HandleCompletedMessage));
-
-  testCounter = 0;
-  observable.BroadcastMessage(MyObservable::MyCustomMessage(12));
-  ASSERT_EQ(12, testCounter);
-
-  // the connection is permanent; if we emit the same message again, the observer will be notified again
-  testCounter = 0;
-  observable.BroadcastMessage(MyObservable::MyCustomMessage(20));
-  ASSERT_EQ(20, testCounter);
-}
-
 TEST(MessageBroker, TestPermanentConnectionDeleteObserver)
 {
-  MessageBroker broker;
-  MyObservable  observable(broker);
-  MyObserver*   observer = new MyObserver(broker);
+  MyObservable  observable;
+  boost::shared_ptr<MyObserver>  observer(new MyObserver);
 
   // create a permanent connection between an observable and an observer
-  observable.RegisterObserverCallback(new Callable<MyObserver, MyObservable::MyCustomMessage>(*observer, &MyObserver::HandleCompletedMessage));
+  observer->Register<MyObservable::MyCustomMessage>(observable, &MyObserver::HandleCompletedMessage);
 
   testCounter = 0;
   observable.BroadcastMessage(MyObservable::MyCustomMessage(12));
   ASSERT_EQ(12, testCounter);
 
   // delete the observer and check that the callback is not called anymore
-  delete observer;
+  observer.reset();
 
   // the connection is permanent; if we emit the same message again, the observer will be notified again
   testCounter = 0;
   observable.BroadcastMessage(MyObservable::MyCustomMessage(20));
   ASSERT_EQ(0, testCounter);
 }
-
-TEST(MessageBroker, TestMessageForwarderDeleteIntermediate)
-{
-  MessageBroker broker;
-  MyObservable  observable(broker);
-  MyIntermediate* intermediate = new MyIntermediate(broker, observable);
-  MyObserver    observer(broker);
-
-  // let the observer observers the intermediate that is actually forwarding the messages from the observable
-  intermediate->RegisterObserverCallback(new Callable<MyObserver, MyObservable::MyCustomMessage>(observer, &MyObserver::HandleCompletedMessage));
-
-  testCounter = 0;
-  observable.BroadcastMessage(MyObservable::MyCustomMessage(12));
-  ASSERT_EQ(12, testCounter);
-
-  delete intermediate;
-
-  observable.BroadcastMessage(MyObservable::MyCustomMessage(20));
-  ASSERT_EQ(12, testCounter);
-}
-
-TEST(MessageBroker, TestCustomMessage)
-{
-  MessageBroker broker;
-  MyObservable  observable(broker);
-  MyIntermediate intermediate(broker, observable);
-  MyObserver    observer(broker);
-
-  // let the observer observers the intermediate that is actually forwarding the messages from the observable
-  intermediate.RegisterObserverCallback(new Callable<MyObserver, MyObservable::MyCustomMessage>(observer, &MyObserver::HandleCompletedMessage));
-
-  testCounter = 0;
-  observable.BroadcastMessage(MyObservable::MyCustomMessage(12));
-  ASSERT_EQ(12, testCounter);
-
-  // the connection is permanent; if we emit the same message again, the observer will be notified again
-  testCounter = 0;
-  observable.BroadcastMessage(MyObservable::MyCustomMessage(20));
-  ASSERT_EQ(20, testCounter);
-}
-
-
-#if 0 /* __cplusplus >= 201103L*/
-
-TEST(MessageBroker, TestLambdaSimpleUseCase)
-{
-  MessageBroker broker;
-  MyObservable  observable(broker);
-  MyObserver*   observer = new MyObserver(broker);
-
-  // create a permanent connection between an observable and an observer
-  observable.RegisterObserverCallback(new LambdaCallable<MyObservable::MyCustomMessage>(*observer, [&](const MyObservable::MyCustomMessage& message) {testCounter += 2 * message.payload_;}));
-
-  testCounter = 0;
-  observable.BroadcastMessage(MyObservable::MyCustomMessage(12));
-  ASSERT_EQ(24, testCounter);
-
-  // delete the observer and check that the callback is not called anymore
-  delete observer;
-
-  // the connection is permanent; if we emit the same message again, the observer will be notified again
-  testCounter = 0;
-  observable.BroadcastMessage(MyObservable::MyCustomMessage(20));
-  ASSERT_EQ(0, testCounter);
-}
-
-namespace {
-  class MyObserverWithLambda : public IObserver {
-  private:
-    int multiplier_;  // this is a private variable we want to access in a lambda
-
-  public:
-    MyObserverWithLambda(MessageBroker& broker, int multiplier, MyObservable& observable)
-      : IObserver(broker),
-        multiplier_(multiplier)
-    {
-      // register a callable to a lambda that access private members
-      observable.RegisterObserverCallback(new LambdaCallable<MyObservable::MyCustomMessage>(*this, [this](const MyObservable::MyCustomMessage& message) {
-        testCounter += multiplier_ * message.payload_;
-      }));
-
-    }
-  };
-}
-
-TEST(MessageBroker, TestLambdaCaptureThisAndAccessPrivateMembers)
-{
-  MessageBroker broker;
-  MyObservable  observable(broker);
-  MyObserverWithLambda*   observer = new MyObserverWithLambda(broker, 3, observable);
-
-  testCounter = 0;
-  observable.BroadcastMessage(MyObservable::MyCustomMessage(12));
-  ASSERT_EQ(36, testCounter);
-
-  // delete the observer and check that the callback is not called anymore
-  delete observer;
-
-  // the connection is permanent; if we emit the same message again, the observer will be notified again
-  testCounter = 0;
-  observable.BroadcastMessage(MyObservable::MyCustomMessage(20));
-  ASSERT_EQ(0, testCounter);
-}
-
-#endif // C++ 11