changeset 623:42dadae61fa9

renamed IObservable::EmitMessage() as BroadcastMessage()
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 07 May 2019 14:16:08 +0200
parents 8a3a25f2d42c
children 573e35378999
files Framework/Layers/DicomSeriesVolumeSlicer.cpp Framework/Layers/DicomStructureSetSlicer.cpp Framework/Layers/DicomStructureSetSlicer.h Framework/Messages/IObservable.cpp Framework/Messages/IObservable.h Framework/Messages/MessageForwarder.cpp Framework/Radiography/RadiographyAlphaLayer.cpp Framework/Radiography/RadiographyDicomLayer.cpp Framework/Radiography/RadiographyLayer.cpp Framework/Radiography/RadiographyMaskLayer.cpp Framework/Radiography/RadiographyScene.cpp Framework/SmartLoader.cpp Framework/Toolbox/OrthancSlicesLoader.cpp Framework/Viewport/IViewport.h Framework/Volumes/StructureSetLoader.cpp Framework/Widgets/SliceViewerWidget.cpp Samples/Sdl/Loader.cpp
diffstat 17 files changed, 150 insertions(+), 73 deletions(-) [+]
line wrap: on
line diff
--- a/Framework/Layers/DicomSeriesVolumeSlicer.cpp	Tue May 07 12:32:21 2019 +0200
+++ b/Framework/Layers/DicomSeriesVolumeSlicer.cpp	Tue May 07 14:16:08 2019 +0200
@@ -36,17 +36,17 @@
   {
     if (message.GetOrigin().GetSliceCount() > 0)
     {
-      EmitMessage(IVolumeSlicer::GeometryReadyMessage(*this));
+      BroadcastMessage(IVolumeSlicer::GeometryReadyMessage(*this));
     }
     else
     {
-      EmitMessage(IVolumeSlicer::GeometryErrorMessage(*this));
+      BroadcastMessage(IVolumeSlicer::GeometryErrorMessage(*this));
     }
   }
 
   void DicomSeriesVolumeSlicer::OnSliceGeometryError(const OrthancSlicesLoader::SliceGeometryErrorMessage& message)
   {
-    EmitMessage(IVolumeSlicer::GeometryErrorMessage(*this));
+    BroadcastMessage(IVolumeSlicer::GeometryErrorMessage(*this));
   }
 
 
@@ -73,17 +73,17 @@
   void DicomSeriesVolumeSlicer::OnSliceImageReady(const OrthancSlicesLoader::SliceImageReadyMessage& message)
   {
     // first notify that the pixel data of the frame is ready (targeted to, i.e: an image cache)
-    EmitMessage(FrameReadyMessage(*this, message.GetImage(), 
+    BroadcastMessage(FrameReadyMessage(*this, message.GetImage(), 
                                   message.GetEffectiveQuality(), message.GetSlice()));
 
     // then notify that the layer is ready for rendering
     RendererFactory factory(message);
-    EmitMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, message.GetSlice().GetGeometry()));
+    BroadcastMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, message.GetSlice().GetGeometry()));
   }
 
   void DicomSeriesVolumeSlicer::OnSliceImageError(const OrthancSlicesLoader::SliceImageErrorMessage& message)
   {
-    EmitMessage(IVolumeSlicer::LayerErrorMessage(*this, message.GetSlice().GetGeometry()));
+    BroadcastMessage(IVolumeSlicer::LayerErrorMessage(*this, message.GetSlice().GetGeometry()));
   }
 
 
--- a/Framework/Layers/DicomStructureSetSlicer.cpp	Tue May 07 12:32:21 2019 +0200
+++ b/Framework/Layers/DicomStructureSetSlicer.cpp	Tue May 07 14:16:08 2019 +0200
@@ -164,7 +164,7 @@
     if (loader_.HasStructureSet())
     {
       RendererFactory factory(loader_.GetStructureSet(), viewportPlane);
-      EmitMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, viewportPlane));
+      BroadcastMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, viewportPlane));
     }
   }
 }
--- a/Framework/Layers/DicomStructureSetSlicer.h	Tue May 07 12:32:21 2019 +0200
+++ b/Framework/Layers/DicomStructureSetSlicer.h	Tue May 07 14:16:08 2019 +0200
@@ -38,7 +38,7 @@
 
     void OnStructureSetLoaded(const IVolumeLoader::ContentChangedMessage& message)
     {
-      EmitMessage(IVolumeSlicer::ContentChangedMessage(*this));
+      BroadcastMessage(IVolumeSlicer::ContentChangedMessage(*this));
     }
 
   public:
--- a/Framework/Messages/IObservable.cpp	Tue May 07 12:32:21 2019 +0200
+++ b/Framework/Messages/IObservable.cpp	Tue May 07 14:16:08 2019 +0200
@@ -84,7 +84,8 @@
     }
   }
   
-  void IObservable::EmitMessage(const IMessage& message)
+  void IObservable::EmitMessageInternal(const IObserver* receiver,
+                                        const IMessage& message)
   {
     Callables::const_iterator found = callables_.find(message.GetType());
 
@@ -94,14 +95,33 @@
              it = found->second.begin(); it != found->second.end(); ++it)
       {
         assert(*it != NULL);
-        if (broker_.IsActive(*(*it)->GetObserver()))
+
+        const IObserver* observer = (*it)->GetObserver();
+        if (broker_.IsActive(*observer))
         {
-          (*it)->Apply(message);
+          if (receiver == NULL ||    // Are we broadcasting?
+              observer == receiver)  // Not broadcasting, but this is the receiver
+          {
+            (*it)->Apply(message);
+          }
         }
       }
     }
   }
 
+
+  void IObservable::BroadcastMessage(const IMessage& message)
+  {
+    EmitMessageInternal(NULL, message);
+  }
+
+  
+  void IObservable::EmitMessage(const IObserver& observer,
+                                const IMessage& message)
+  {
+    EmitMessageInternal(&observer, message);
+  }
+
   
   void IObservable::RegisterForwarder(IMessageForwarder* forwarder)
   {
--- a/Framework/Messages/IObservable.h	Tue May 07 12:32:21 2019 +0200
+++ b/Framework/Messages/IObservable.h	Tue May 07 14:16:08 2019 +0200
@@ -42,6 +42,9 @@
     Callables       callables_;
     Forwarders      forwarders_;
 
+    void EmitMessageInternal(const IObserver* receiver,
+                             const IMessage& message);
+
   public:
     IObservable(MessageBroker& broker) :
       broker_(broker)
@@ -60,7 +63,10 @@
 
     void Unregister(IObserver* observer);
 
-    void EmitMessage(const IMessage& message);
+    void BroadcastMessage(const IMessage& message);
+
+    void EmitMessage(const IObserver& observer,
+                     const IMessage& message);
 
     // Takes ownsership
     void RegisterForwarder(IMessageForwarder* forwarder);
--- a/Framework/Messages/MessageForwarder.cpp	Tue May 07 12:32:21 2019 +0200
+++ b/Framework/Messages/MessageForwarder.cpp	Tue May 07 14:16:08 2019 +0200
@@ -28,7 +28,7 @@
 
   void IMessageForwarder::ForwardMessageInternal(const IMessage& message)
   {
-    emitter_.EmitMessage(message);
+    emitter_.BroadcastMessage(message);
   }
 
   void IMessageForwarder::RegisterForwarderInEmitter()
--- a/Framework/Radiography/RadiographyAlphaLayer.cpp	Tue May 07 12:32:21 2019 +0200
+++ b/Framework/Radiography/RadiographyAlphaLayer.cpp	Tue May 07 14:16:08 2019 +0200
@@ -46,7 +46,7 @@
     SetSize(image->GetWidth(), image->GetHeight());
     alpha_ = raii;
 
-    EmitMessage(RadiographyLayer::LayerEditedMessage(*this));
+    BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this));
   }
 
   void RadiographyAlphaLayer::Render(Orthanc::ImageAccessor& buffer,
--- a/Framework/Radiography/RadiographyDicomLayer.cpp	Tue May 07 12:32:21 2019 +0200
+++ b/Framework/Radiography/RadiographyDicomLayer.cpp	Tue May 07 14:16:08 2019 +0200
@@ -103,7 +103,7 @@
     source_ = raii;
     ApplyConverter();
 
-    EmitMessage(RadiographyLayer::LayerEditedMessage(*this));
+    BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this));
   }
 
   void RadiographyDicomLayer::Render(Orthanc::ImageAccessor& buffer,
--- a/Framework/Radiography/RadiographyLayer.cpp	Tue May 07 12:32:21 2019 +0200
+++ b/Framework/Radiography/RadiographyLayer.cpp	Tue May 07 14:16:08 2019 +0200
@@ -139,7 +139,7 @@
   {
     prefferedPhotometricDisplayMode_ = prefferedPhotometricDisplayMode;
 
-    EmitMessage(RadiographyLayer::LayerEditedMessage(*this));
+    BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this));
   }
 
   void RadiographyLayer::SetCrop(unsigned int x,
@@ -161,7 +161,7 @@
     geometry_.SetCrop(x, y, width, height);
     UpdateTransform();
 
-    EmitMessage(RadiographyLayer::LayerEditedMessage(*this));
+    BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this));
   }
 
   void RadiographyLayer::SetGeometry(const Geometry& geometry)
@@ -173,7 +173,7 @@
       UpdateTransform();
     }
 
-    EmitMessage(RadiographyLayer::LayerEditedMessage(*this));
+    BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this));
   }
 
 
@@ -201,7 +201,7 @@
     geometry_.SetAngle(angle);
     UpdateTransform();
 
-    EmitMessage(RadiographyLayer::LayerEditedMessage(*this));
+    BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this));
   }
 
 
@@ -220,7 +220,7 @@
     height_ = height;
 
     UpdateTransform();
-    EmitMessage(RadiographyLayer::LayerEditedMessage(*this));
+    BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this));
   }
 
 
@@ -298,7 +298,7 @@
   {
     geometry_.SetPan(x, y);
     UpdateTransform();
-    EmitMessage(RadiographyLayer::LayerEditedMessage(*this));
+    BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this));
   }
 
 
@@ -307,7 +307,7 @@
   {
     geometry_.SetPixelSpacing(x, y);
     UpdateTransform();
-    EmitMessage(RadiographyLayer::LayerEditedMessage(*this));
+    BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this));
   }
 
 
--- a/Framework/Radiography/RadiographyMaskLayer.cpp	Tue May 07 12:32:21 2019 +0200
+++ b/Framework/Radiography/RadiographyMaskLayer.cpp	Tue May 07 14:16:08 2019 +0200
@@ -63,7 +63,7 @@
       corners_.push_back(corner);
     invalidated_ = true;
 
-    EmitMessage(RadiographyLayer::LayerEditedMessage(*this));
+    BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this));
   }
 
   void RadiographyMaskLayer::SetCorners(const std::vector<Orthanc::ImageProcessing::ImagePoint>& corners)
@@ -71,7 +71,7 @@
     corners_ = corners;
     invalidated_ = true;
 
-    EmitMessage(RadiographyLayer::LayerEditedMessage(*this));
+    BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this));
   }
 
   void RadiographyMaskLayer::Render(Orthanc::ImageAccessor& buffer,
--- a/Framework/Radiography/RadiographyScene.cpp	Tue May 07 12:32:21 2019 +0200
+++ b/Framework/Radiography/RadiographyScene.cpp	Tue May 07 14:16:08 2019 +0200
@@ -140,8 +140,8 @@
     raii->SetIndex(index);
     layers_[index] = raii.release();
 
-    EmitMessage(GeometryChangedMessage(*this, *layer));
-    EmitMessage(ContentChangedMessage(*this, *layer));
+    BroadcastMessage(GeometryChangedMessage(*this, *layer));
+    BroadcastMessage(ContentChangedMessage(*this, *layer));
     layer->RegisterObserverCallback(new Callable<RadiographyScene, RadiographyLayer::LayerEditedMessage>(*this, &RadiographyScene::OnLayerEdited));
 
     return *layer;
@@ -149,7 +149,7 @@
 
   void RadiographyScene::OnLayerEdited(const RadiographyLayer::LayerEditedMessage& message)
   {
-    EmitMessage(RadiographyScene::LayerEditedMessage(*this, message.GetOrigin()));
+    BroadcastMessage(RadiographyScene::LayerEditedMessage(*this, message.GetOrigin()));
   }
 
   RadiographyScene::RadiographyScene(MessageBroker& broker) :
@@ -266,7 +266,7 @@
     windowingCenter_ = center;
     windowingWidth_ = width;
 
-    EmitMessage(RadiographyScene::WindowingChangedMessage(*this));
+    BroadcastMessage(RadiographyScene::WindowingChangedMessage(*this));
   }
 
 
@@ -447,7 +447,7 @@
         windowingWidth_ = w;
       }
 
-      EmitMessage(GeometryChangedMessage(*this, *(layer->second)));
+      BroadcastMessage(GeometryChangedMessage(*this, *(layer->second)));
     }
   }
 
@@ -474,7 +474,7 @@
       reader->ReadFromMemory(content);
       dynamic_cast<RadiographyDicomLayer*>(layer->second)->SetSourceImage(reader.release());
 
-      EmitMessage(ContentChangedMessage(*this, *(layer->second)));
+      BroadcastMessage(ContentChangedMessage(*this, *(layer->second)));
     }
   }
 
--- a/Framework/SmartLoader.cpp	Tue May 07 12:32:21 2019 +0200
+++ b/Framework/SmartLoader.cpp	Tue May 07 14:16:08 2019 +0200
@@ -95,7 +95,7 @@
         LOG(WARNING) << "ScheduleLayerCreation for CachedSlice (image is loaded): " << slice_->GetOrthancInstanceId();
 
         RendererFactory factory(*this);   
-        EmitMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, slice_->GetGeometry()));
+        BroadcastMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, slice_->GetGeometry()));
       }
       else
       {
@@ -174,7 +174,7 @@
 
     if (cachedSlice != NULL)
     {
-      EmitMessage(IVolumeSlicer::GeometryReadyMessage(*cachedSlice));
+      BroadcastMessage(IVolumeSlicer::GeometryReadyMessage(*cachedSlice));
     }
 
   }
@@ -242,7 +242,7 @@
     cachedSlices_[sliceKeyId] = boost::shared_ptr<CachedSlice>(cachedSlice);
 
     // re-emit original Layer message to observers
-    EmitMessage(message);
+    BroadcastMessage(message);
   }
 
 
@@ -264,7 +264,7 @@
     cachedSlices_[sliceKeyId] = cachedSlice;
 
     // re-emit original Layer message to observers
-    EmitMessage(message);
+    BroadcastMessage(message);
   }
 
 
@@ -286,6 +286,6 @@
     }
 
     // re-emit original Layer message to observers
-    EmitMessage(message);
+    BroadcastMessage(message);
   }
 }
--- a/Framework/Toolbox/OrthancSlicesLoader.cpp	Tue May 07 12:32:21 2019 +0200
+++ b/Framework/Toolbox/OrthancSlicesLoader.cpp	Tue May 07 14:16:08 2019 +0200
@@ -177,7 +177,7 @@
   {
     OrthancSlicesLoader::SliceImageReadyMessage msg
       (*this, operation.GetSliceIndex(), operation.GetSlice(), image, operation.GetQuality());
-    EmitMessage(msg);
+    BroadcastMessage(msg);
   }
   
   
@@ -185,7 +185,7 @@
   {
     OrthancSlicesLoader::SliceImageErrorMessage msg
       (*this, operation.GetSliceIndex(), operation.GetSlice(), operation.GetQuality());
-    EmitMessage(msg);
+    BroadcastMessage(msg);
   }
   
   
@@ -210,18 +210,18 @@
     if (ok)
     {
       LOG(INFO) << "Loaded a series with " << slices_.GetSliceCount() << " slice(s)";
-      EmitMessage(SliceGeometryReadyMessage(*this));
+      BroadcastMessage(SliceGeometryReadyMessage(*this));
     }
     else
     {
       LOG(ERROR) << "This series is empty";
-      EmitMessage(SliceGeometryErrorMessage(*this));
+      BroadcastMessage(SliceGeometryErrorMessage(*this));
     }
   }
   
   void OrthancSlicesLoader::OnGeometryError(const IWebService::HttpRequestErrorMessage& message)
   {
-    EmitMessage(SliceGeometryErrorMessage(*this));
+    BroadcastMessage(SliceGeometryErrorMessage(*this));
     state_ = State_Error;
   }
 
@@ -296,7 +296,7 @@
       else
       {
         LOG(WARNING) << "Skipping invalid multi-frame instance " << instanceId;
-        EmitMessage(SliceGeometryErrorMessage(*this));
+        BroadcastMessage(SliceGeometryErrorMessage(*this));
         return;
       }
     }
@@ -323,12 +323,12 @@
     {
       LOG(INFO) << "Loaded instance geometry " << instanceId;
       slices_.AddSlice(slice.release());
-      EmitMessage(SliceGeometryReadyMessage(*this));
+      BroadcastMessage(SliceGeometryReadyMessage(*this));
     }
     else
     {
       LOG(WARNING) << "Skipping invalid instance " << instanceId;
-      EmitMessage(SliceGeometryErrorMessage(*this));
+      BroadcastMessage(SliceGeometryErrorMessage(*this));
     }
   }
   
--- a/Framework/Viewport/IViewport.h	Tue May 07 12:32:21 2019 +0200
+++ b/Framework/Viewport/IViewport.h	Tue May 07 14:16:08 2019 +0200
@@ -89,7 +89,7 @@
     // TODO Why should this be virtual?
     virtual void NotifyContentChanged()
     {
-      EmitMessage(ViewportChangedMessage(*this));
+      BroadcastMessage(ViewportChangedMessage(*this));
     }
   };
 }
--- a/Framework/Volumes/StructureSetLoader.cpp	Tue May 07 12:32:21 2019 +0200
+++ b/Framework/Volumes/StructureSetLoader.cpp	Tue May 07 14:16:08 2019 +0200
@@ -44,7 +44,7 @@
     MessagingToolbox::ConvertDataset(slice, dataset);
     structureSet_->AddReferencedSlice(slice);
 
-    EmitMessage(ContentChangedMessage(*this));
+    BroadcastMessage(ContentChangedMessage(*this));
   }
   
 
@@ -63,7 +63,7 @@
                             new Callable<StructureSetLoader, OrthancApiClient::JsonResponseReadyMessage>(*this, &StructureSetLoader::OnLookupCompleted));
     }
 
-    EmitMessage(GeometryReadyMessage(*this));
+    BroadcastMessage(GeometryReadyMessage(*this));
   }
 
   
--- a/Framework/Widgets/SliceViewerWidget.cpp	Tue May 07 12:32:21 2019 +0200
+++ b/Framework/Widgets/SliceViewerWidget.cpp	Tue May 07 14:16:08 2019 +0200
@@ -527,7 +527,7 @@
       InvalidateAllLayers();   // TODO Removing this line avoid loading twice the image in WASM
     }
 
-    EmitMessage(DisplayedSliceMessage(*this, displayedSlice));
+    BroadcastMessage(DisplayedSliceMessage(*this, displayedSlice));
   }
 
 
@@ -541,7 +541,7 @@
       changedLayers_[i] = true;
       //layers_[i]->ScheduleLayerCreation(plane_);
     }
-    EmitMessage(GeometryChangedMessage(*this));
+    BroadcastMessage(GeometryChangedMessage(*this));
   }
   
 
@@ -579,7 +579,7 @@
       InvalidateLayer(index);
     }
     
-    EmitMessage(SliceViewerWidget::ContentChangedMessage(*this));
+    BroadcastMessage(SliceViewerWidget::ContentChangedMessage(*this));
   }
   
 
@@ -594,7 +594,7 @@
       }
     }
     
-    EmitMessage(SliceViewerWidget::ContentChangedMessage(*this));
+    BroadcastMessage(SliceViewerWidget::ContentChangedMessage(*this));
   }
   
   
@@ -607,7 +607,7 @@
       UpdateLayer(index, message.CreateRenderer(), message.GetSlice());
     }
     
-    EmitMessage(SliceViewerWidget::ContentChangedMessage(*this));
+    BroadcastMessage(SliceViewerWidget::ContentChangedMessage(*this));
   }
 
 
@@ -621,7 +621,7 @@
       // TODO
       //UpdateLayer(index, new SliceOutlineRenderer(slice), slice);
 
-      EmitMessage(SliceViewerWidget::ContentChangedMessage(*this));
+      BroadcastMessage(SliceViewerWidget::ContentChangedMessage(*this));
     }
   }
 
--- a/Samples/Sdl/Loader.cpp	Tue May 07 12:32:21 2019 +0200
+++ b/Samples/Sdl/Loader.cpp	Tue May 07 14:16:08 2019 +0200
@@ -24,6 +24,7 @@
 #include "../../Framework/Messages/MessageBroker.h"
 #include "../../Framework/Messages/ICallable.h"
 #include "../../Framework/Messages/IObservable.h"
+#include "../../Framework/Volumes/ImageBuffer3D.h"
 
 // From Orthanc framework
 #include <Core/IDynamicObject.h>
@@ -69,7 +70,8 @@
     {
     }
 
-    virtual void EmitMessage(const OrthancStone::IMessage& message) = 0;
+    virtual void EmitMessage(const OrthancStone::IObserver& observer,
+                             const OrthancStone::IMessage& message) = 0;
   };
 
 
@@ -80,7 +82,8 @@
     {
     }
 
-    virtual void Schedule(IOracleCommand* command) = 0;  // Takes ownership
+    virtual void Schedule(const OrthancStone::IObserver& receiver,
+                          IOracleCommand* command) = 0;  // Takes ownership
   };
 
 
@@ -285,11 +288,14 @@
     class Item : public Orthanc::IDynamicObject
     {
     private:
-      std::auto_ptr<IOracleCommand>  command_;
+      const OrthancStone::IObserver&  receiver_;
+      std::auto_ptr<IOracleCommand>   command_;
 
     public:
-      Item(IOracleCommand* command) :
-      command_(command)
+      Item(const OrthancStone::IObserver& receiver,
+           IOracleCommand* command) :
+        receiver_(receiver),
+        command_(command)
       {
         if (command == NULL)
         {
@@ -297,7 +303,12 @@
         }
       }
 
-      const IOracleCommand& GetCommand()
+      const OrthancStone::IObserver& GetReceiver() const
+      {
+        return receiver_;
+      }
+
+      const IOracleCommand& GetCommand() const
       {
         assert(command_.get() != NULL);
         return *command_;
@@ -321,7 +332,8 @@
     std::vector<boost::thread*>    workers_;
 
 
-    void Execute(const OrthancApiOracleCommand& command)
+    void Execute(const OrthancStone::IObserver& receiver,
+                 const OrthancApiOracleCommand& command)
     {
       Orthanc::HttpClient  client(orthanc_, command.GetUri());
       client.SetMethod(command.GetMethod());
@@ -352,12 +364,12 @@
       if (success)
       {
         OrthancApiOracleCommand::SuccessMessage message(command, answerHeaders, answer);
-        emitter_.EmitMessage(message);
+        emitter_.EmitMessage(receiver, message);
       }
       else
       {
         OrthancApiOracleCommand::FailureMessage message(command, client.GetLastStatus());
-        emitter_.EmitMessage(message);
+        emitter_.EmitMessage(receiver, message);
       }
     }
 
@@ -365,16 +377,17 @@
 
     void Step()
     {
-      std::auto_ptr<Orthanc::IDynamicObject>  item(queue_.Dequeue(100));
+      std::auto_ptr<Orthanc::IDynamicObject>  object(queue_.Dequeue(100));
 
-      if (item.get() != NULL)
+      if (object.get() != NULL)
       {
-        const IOracleCommand& command = dynamic_cast<Item*>(item.get())->GetCommand();
+        const Item& item = dynamic_cast<Item&>(*object);
 
-        switch (command.GetType())
+        switch (item.GetCommand().GetType())
         {
           case IOracleCommand::Type_OrthancApi:
-            Execute(dynamic_cast<const OrthancApiOracleCommand&>(command));
+            Execute(item.GetReceiver(), 
+                    dynamic_cast<const OrthancApiOracleCommand&>(item.GetCommand()));
             break;
 
           default:
@@ -503,9 +516,10 @@
       StopInternal();
     }
 
-    virtual void Schedule(IOracleCommand* command)
+    virtual void Schedule(const OrthancStone::IObserver& receiver,
+                          IOracleCommand* command)
     {
-      queue_.Enqueue(new Item(command));
+      queue_.Enqueue(new Item(receiver, command));
     }
   };
 
@@ -525,10 +539,11 @@
     }
 
 
-    virtual void EmitMessage(const OrthancStone::IMessage& message)
+    virtual void EmitMessage(const OrthancStone::IObserver& observer,
+                             const OrthancStone::IMessage& message)
     {
       boost::unique_lock<boost::shared_mutex>  lock(mutex_);
-      oracleObservable_.EmitMessage(message);
+      oracleObservable_.EmitMessage(observer, message);
     }
 
 
@@ -571,6 +586,34 @@
       }
     };
   };
+
+
+
+  class AxialVolumeOrthancLoader : public OrthancStone::IObserver
+  {
+  private:
+    void Handle(const Refactoring::OrthancApiOracleCommand::SuccessMessage& message)
+    {
+      Json::Value v;
+      message.GetJsonBody(v);
+
+      printf("ICI [%s]\n", v.toStyledString().c_str());
+    }
+
+
+    std::auto_ptr<OrthancStone::ImageBuffer3D>  image_;
+
+
+  public:
+    AxialVolumeOrthancLoader(OrthancStone::IObservable& oracle) :
+      IObserver(oracle.GetBroker())
+    {
+      oracle.RegisterObserverCallback(
+        new OrthancStone::Callable<AxialVolumeOrthancLoader, OrthancApiOracleCommand::SuccessMessage>
+        (*this, &AxialVolumeOrthancLoader::Handle));
+    }
+  };
+
 }
 
 
@@ -595,8 +638,9 @@
   Toto(OrthancStone::IObservable& oracle) :
     IObserver(oracle.GetBroker())
   {
-    oracle.RegisterObserverCallback(new OrthancStone::Callable<Toto, Refactoring::OrthancApiOracleCommand::SuccessMessage>(*this, &Toto::Handle));
-    oracle.RegisterObserverCallback(new OrthancStone::Callable<Toto, Refactoring::OrthancApiOracleCommand::FailureMessage>(*this, &Toto::Handle));
+    oracle.RegisterObserverCallback
+      (new OrthancStone::Callable
+       <Toto, Refactoring::OrthancApiOracleCommand::SuccessMessage>(*this, &Toto::Handle));
   }
 };
 
@@ -610,6 +654,13 @@
     toto.reset(new Toto(lock.GetOracleObservable()));
   }
 
+  std::auto_ptr<Refactoring::AxialVolumeOrthancLoader> loader;
+
+  {
+    Refactoring::NativeApplicationContext::WriterLock lock(context);
+    loader.reset(new Refactoring::AxialVolumeOrthancLoader(lock.GetOracleObservable()));
+  }
+
   Refactoring::NativeOracle oracle(context);
 
   {
@@ -631,7 +682,7 @@
     command->SetUri("/tools/find");
     command->SetBody(v);
 
-    oracle.Schedule(command.release());
+    oracle.Schedule(*toto, command.release());
   }
 
   boost::this_thread::sleep(boost::posix_time::seconds(1));