changeset 795:bc20e4c417ec

refactoring OrthancMultiframeVolumeLoader using LoaderStateMachine
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 28 May 2019 13:02:56 +0200
parents 04f518ebd132
children d3197e0e321d 11fc84650e4b
files Samples/Sdl/Loader.cpp
diffstat 1 files changed, 91 insertions(+), 99 deletions(-) [+]
line wrap: on
line diff
--- a/Samples/Sdl/Loader.cpp	Tue May 28 12:26:16 2019 +0200
+++ b/Samples/Sdl/Loader.cpp	Tue May 28 13:02:56 2019 +0200
@@ -989,10 +989,21 @@
       {
       }
 
-      void Schedule(OracleCommandWithPayload* command)
+      State(const State& currentState) :
+        that_(currentState.that_)
+      {
+      }
+
+      void Schedule(OracleCommandWithPayload* command) const
       {
         that_.Schedule(command);
       }
+
+      template <typename T>
+      T& GetLoader() const
+      {
+        return dynamic_cast<T&>(that_);
+      }
       
       virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const
       {
@@ -1013,6 +1024,11 @@
     void Schedule(OracleCommandWithPayload* command)
     {
       std::auto_ptr<OracleCommandWithPayload> protection(command);
+
+      if (command == NULL)
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
+      }
       
       if (!command->HasPayload())
       {
@@ -1021,6 +1037,7 @@
       }
 
       pendingCommands_.push_back(protection.release());
+      Step();
     }
 
     void Start()
@@ -1030,6 +1047,8 @@
         throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
       }
 
+      active_ = true;
+
       for (size_t i = 0; i < simultaneousDownloads_; i++)
       {
         Step();
@@ -1039,28 +1058,36 @@
   private:
     void Step()
     {
-      if (!pendingCommands_.empty())
+      if (!pendingCommands_.empty() &&
+          activeCommands_ < simultaneousDownloads_)
       {
         oracle_.Schedule(*this, pendingCommands_.front());
         pendingCommands_.pop_front();
+
+        activeCommands_++;
       }
     }
-    
-    void Handle(const OrthancRestApiCommand::SuccessMessage& message)
-    {
-      dynamic_cast<const State&>(message.GetOrigin().GetPayload()).Handle(message);
-      Step();
-    }
 
-    void Handle(const GetOrthancImageCommand::SuccessMessage& message)
+    void Clear()
+    {
+      for (PendingCommands::iterator it = pendingCommands_.begin();
+           it != pendingCommands_.end(); ++it)
+      {
+        delete *it;
+      }
+    }
+
+    void HandleException(const OracleCommandExceptionMessage& message)
+    {
+      LOG(ERROR) << "Error in the state machine, stopping all processing";
+      Clear();
+    }
+
+    template <typename T>
+    void Handle(const T& message)
     {
       dynamic_cast<const State&>(message.GetOrigin().GetPayload()).Handle(message);
-      Step();
-    }
-
-    void Handle(const GetOrthancWebViewerJpegCommand::SuccessMessage& message)
-    {
-      dynamic_cast<const State&>(message.GetOrigin().GetPayload()).Handle(message);
+      activeCommands_--;
       Step();
     }
 
@@ -1070,6 +1097,7 @@
     bool             active_;
     unsigned int     simultaneousDownloads_;
     PendingCommands  pendingCommands_;
+    unsigned int     activeCommands_;
 
   public:
     LoaderStateMachine(IOracle& oracle,
@@ -1077,31 +1105,37 @@
       IObserver(oracleObservable.GetBroker()),
       oracle_(oracle),
       active_(false),
-      simultaneousDownloads_(4)
+      simultaneousDownloads_(4),
+      activeCommands_(0)
     {
       oracleObservable.RegisterObserverCallback(
         new Callable<LoaderStateMachine, OrthancRestApiCommand::SuccessMessage>
-        (*this, &LoaderStateMachine::Handle));
+        (*this, &LoaderStateMachine::Handle<OrthancRestApiCommand::SuccessMessage>));
 
       oracleObservable.RegisterObserverCallback(
         new Callable<LoaderStateMachine, GetOrthancImageCommand::SuccessMessage>
-        (*this, &LoaderStateMachine::Handle));
+        (*this, &LoaderStateMachine::Handle<GetOrthancImageCommand::SuccessMessage>));
 
       oracleObservable.RegisterObserverCallback(
         new Callable<LoaderStateMachine, GetOrthancWebViewerJpegCommand::SuccessMessage>
-        (*this, &LoaderStateMachine::Handle));
+        (*this, &LoaderStateMachine::Handle<GetOrthancWebViewerJpegCommand::SuccessMessage>));
+
+      oracleObservable.RegisterObserverCallback(
+        new Callable<LoaderStateMachine, OracleCommandExceptionMessage>
+        (*this, &LoaderStateMachine::HandleException));
     }
 
     virtual ~LoaderStateMachine()
     {
-      for (PendingCommands::iterator it = pendingCommands_.begin();
-           it != pendingCommands_.end(); ++it)
-      {
-        delete *it;
-      }
+      Clear();
     }
 
-    virtual void SetSimultaneousDownloads(unsigned int count)
+    bool IsActive() const
+    {
+      return active_;
+    }
+
+    void SetSimultaneousDownloads(unsigned int count)
     {
       if (active_)
       {
@@ -1121,41 +1155,10 @@
 
 
   class OrthancMultiframeVolumeLoader :
-    public IObserver,
+    public LoaderStateMachine,
     public IObservable
   {
   private:
-    class State : public Orthanc::IDynamicObject
-    {
-    private:
-      OrthancMultiframeVolumeLoader&  that_;
-
-    protected:
-      void Schedule(OrthancRestApiCommand* command) const
-      {
-        that_.oracle_.Schedule(that_, command);
-      }
-
-      OrthancMultiframeVolumeLoader& GetTarget() const
-      {
-        return that_;
-      }
-
-    public:
-      State(OrthancMultiframeVolumeLoader& that) :
-        that_(that)
-      {
-      }
-      
-      virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const = 0;
-    };
-    
-    void Handle(const OrthancRestApiCommand::SuccessMessage& message)
-    {
-      dynamic_cast<const State&>(message.GetOrigin().GetPayload()).Handle(message);
-    }
-
-
     class LoadRTDoseGeometry : public State
     {
     private:
@@ -1171,6 +1174,7 @@
         {
           throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
         }
+
       }
 
       virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const
@@ -1179,7 +1183,7 @@
         std::string s = Orthanc::Toolbox::StripSpaces(message.GetAnswer());
         dicom_->SetValue(Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR, s, false);
 
-        GetTarget().SetGeometry(*dicom_);
+        GetLoader<OrthancMultiframeVolumeLoader>().SetGeometry(*dicom_);
       }      
     };
 
@@ -1209,6 +1213,8 @@
       
       virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const
       {
+        OrthancMultiframeVolumeLoader& loader = GetLoader<OrthancMultiframeVolumeLoader>();
+        
         Json::Value body;
         message.ParseJsonBody(body);
         
@@ -1226,15 +1232,15 @@
           // mandatory for RT-DOSE, but is too long to be returned by default
           
           std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand);
-          command->SetUri("/instances/" + GetTarget().GetInstanceId() + "/content/" +
+          command->SetUri("/instances/" + loader.GetInstanceId() + "/content/" +
                           Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR.Format());
-          command->SetPayload(new LoadRTDoseGeometry(GetTarget(), dicom.release()));
+          command->SetPayload(new LoadRTDoseGeometry(loader, dicom.release()));
 
           Schedule(command.release());
         }
         else
         {
-          GetTarget().SetGeometry(*dicom);
+          loader.SetGeometry(*dicom);
         }
       }
     };
@@ -1251,7 +1257,7 @@
       
       virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const
       {
-        GetTarget().SetTransferSyntax(message.GetAnswer());
+        GetLoader<OrthancMultiframeVolumeLoader>().SetTransferSyntax(message.GetAnswer());
       }
     };
    
@@ -1266,22 +1272,20 @@
       
       virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const
       {
-        GetTarget().SetUncompressedPixelData(message.GetAnswer());
+        GetLoader<OrthancMultiframeVolumeLoader>().SetUncompressedPixelData(message.GetAnswer());
       }
     };
    
     
 
     boost::shared_ptr<DicomVolumeImage>   volume_;
-    IOracle&     oracle_;
-    bool         active_;
     std::string  instanceId_;
     std::string  transferSyntaxUid_;
 
 
     const std::string& GetInstanceId() const
     {
-      if (active_)
+      if (IsActive())
       {
         return instanceId_;
       }
@@ -1309,7 +1313,7 @@
         command->SetUri("/instances/" + instanceId_ + "/content/" +
                         Orthanc::DICOM_TAG_PIXEL_DATA.Format() + "/0");
         command->SetPayload(new LoadUncompressedPixelData(*this));
-        oracle_.Schedule(*this, command.release());
+        Schedule(command.release());
       }
       else
       {
@@ -1451,48 +1455,36 @@
     OrthancMultiframeVolumeLoader(const boost::shared_ptr<DicomVolumeImage>& volume,
                                   IOracle& oracle,
                                   IObservable& oracleObservable) :
-      IObserver(oracleObservable.GetBroker()),
+      LoaderStateMachine(oracle, oracleObservable),
       IObservable(oracleObservable.GetBroker()),
-      volume_(volume),
-      oracle_(oracle),
-      active_(false)
+      volume_(volume)
     {
       if (volume.get() == NULL)
       {
         throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
       }
-      
-      oracleObservable.RegisterObserverCallback(
-        new Callable<OrthancMultiframeVolumeLoader, OrthancRestApiCommand::SuccessMessage>
-        (*this, &OrthancMultiframeVolumeLoader::Handle));
     }
 
 
     void LoadInstance(const std::string& instanceId)
     {
-      if (active_)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-      else
-      {
-        active_ = true;
-        instanceId_ = instanceId;
+      Start();
+
+      instanceId_ = instanceId;
 
-        {
-          std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand);
-          command->SetHttpHeader("Accept-Encoding", "gzip");
-          command->SetUri("/instances/" + instanceId + "/tags");
-          command->SetPayload(new LoadGeometry(*this));
-          oracle_.Schedule(*this, command.release());
-        }
+      {
+        std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand);
+        command->SetHttpHeader("Accept-Encoding", "gzip");
+        command->SetUri("/instances/" + instanceId + "/tags");
+        command->SetPayload(new LoadGeometry(*this));
+        Schedule(command.release());
+      }
 
-        {
-          std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand);
-          command->SetUri("/instances/" + instanceId + "/metadata/TransferSyntax");
-          command->SetPayload(new LoadTransferSyntax(*this));
-          oracle_.Schedule(*this, command.release());
-        }
+      {
+        std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand);
+        command->SetUri("/instances/" + instanceId + "/metadata/TransferSyntax");
+        command->SetPayload(new LoadTransferSyntax(*this));
+        Schedule(command.release());
       }
     }
   };
@@ -2028,8 +2020,8 @@
     printf("Geometry ready\n");
     
     //plane_ = message.GetOrigin().GetGeometry().GetSagittalGeometry();
-    plane_ = message.GetOrigin().GetGeometry().GetAxialGeometry();
-    //plane_ = message.GetOrigin().GetGeometry().GetCoronalGeometry();
+    //plane_ = message.GetOrigin().GetGeometry().GetAxialGeometry();
+    plane_ = message.GetOrigin().GetGeometry().GetCoronalGeometry();
     plane_.SetOrigin(message.GetOrigin().GetGeometry().GetCoordinates(0.5f, 0.5f, 0.5f));
 
     Refresh();
@@ -2286,7 +2278,7 @@
   // 2017-11-17-Anonymized
   //ctLoader->LoadSeries("cb3ea4d1-d08f3856-ad7b6314-74d88d77-60b05618");  // CT
   doseLoader->LoadInstance("41029085-71718346-811efac4-420e2c15-d39f99b6");  // RT-DOSE
-  rtstructLoader->LoadInstance("83d9c0c3-913a7fee-610097d7-cbf0522d-fd75bee6");  // RT-STRUCT
+  //rtstructLoader->LoadInstance("83d9c0c3-913a7fee-610097d7-cbf0522d-fd75bee6");  // RT-STRUCT
 
   // 2015-01-28-Multiframe
   //doseLoader->LoadInstance("88f71e2a-5fad1c61-96ed14d6-5b3d3cf7-a5825279");  // Multiframe CT