diff UnitTestsSources/TestMessageBroker2_connect_ok.cpp @ 299:3897f9f28cfa am-callable-and-promise

backup work in progress: updated messaging framework with ICallable
author am@osimis.io
date Fri, 14 Sep 2018 16:44:01 +0200
parents
children b70e9be013e4
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UnitTestsSources/TestMessageBroker2_connect_ok.cpp	Fri Sep 14 16:44:01 2018 +0200
@@ -0,0 +1,226 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "gtest/gtest.h"
+
+#include <boost/noncopyable.hpp>
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+
+#include <string>
+#include <map>
+#include <set>
+
+int testCounter = 0;
+namespace {
+
+  enum MessageType
+  {
+    // used in unit tests only
+    MessageType_Test1,
+    MessageType_Test2,
+
+    MessageType_LastGenericStoneMessage
+  };
+
+  struct IMessage  : public boost::noncopyable
+  {
+    MessageType messageType_;
+  public:
+    IMessage(const MessageType& messageType)
+      : messageType_(messageType)
+    {}
+    virtual ~IMessage() {}
+
+    MessageType GetType() const {return messageType_;}
+  };
+
+
+  class IObserver;
+  class IObservable;
+
+  /*
+   * 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 dead observer.
+   */
+  class MessageBroker : public boost::noncopyable
+  {
+
+    std::set<IObserver*> activeObservers_;  // the list of observers that are currently alive (that have not been deleted)
+
+  public:
+
+    void Register(IObserver& observer)
+    {
+      activeObservers_.insert(&observer);
+    }
+
+    void Unregister(IObserver& observer)
+    {
+      activeObservers_.erase(&observer);
+    }
+
+    void EmitMessage(IObservable& from, std::set<IObserver*> observers, const IMessage& message);
+  };
+
+
+  class IObserver : public boost::noncopyable
+  {
+  protected:
+    MessageBroker&                    broker_;
+
+  public:
+    IObserver(MessageBroker& broker)
+      : broker_(broker)
+    {
+      broker_.Register(*this);
+    }
+
+    virtual ~IObserver()
+    {
+      broker_.Unregister(*this);
+    }
+
+    void HandleMessage_(IObservable &from, const IMessage &message)
+    {
+
+      HandleMessage(from, message);
+    }
+
+    virtual void HandleMessage(IObservable& from, const IMessage& message) = 0;
+
+
+  protected:
+
+
+  };
+
+//  struct ICallableObserver
+//  {
+//    IObserver* observer;
+//  };
+
+//  typedef void (IObserver::*ObserverSingleMesssageHandler)(IObservable& from, const IMessage& message);
+
+//  template <typename TObserver>
+//  struct CallableObserver : public ICallableObserver
+//  {
+//    void (TObserver::*ptrToMemberHandler)(IObservable& from, const IMessage& message);
+//  };
+
+  struct CallableObserver
+  {
+    IObserver* observer;
+    boost::function<void (IObservable& from, const IMessage& message)> f;
+  };
+
+  class IObservable : public boost::noncopyable
+  {
+  protected:
+    MessageBroker&                     broker_;
+
+    std::set<IObserver*>              observers_;
+
+    std::map<MessageType, std::set<CallableObserver*> > callables_;
+  public:
+
+    IObservable(MessageBroker& broker)
+      : broker_(broker)
+    {
+    }
+    virtual ~IObservable()
+    {
+    }
+
+    void EmitMessage(const IMessage& message)
+    {
+      //broker_.EmitMessage(*this, observers_, message);
+
+      // TODO check if observer is still alive and call !
+      CallableObserver* callable = *(callables_[message.GetType()].begin());
+      callable->f(*this, message);
+    }
+
+    void RegisterObserver(IObserver& observer)
+    {
+      observers_.insert(&observer);
+    }
+
+    void UnregisterObserver(IObserver& observer)
+    {
+      observers_.erase(&observer);
+    }
+
+
+    //template<typename TObserver> void Connect(MessageType messageType, IObserver& observer, void (TObserver::*ptrToMemberHandler)(IObservable& from, const IMessage& message))
+    void Connect(MessageType messageType, IObserver& observer, boost::function<void (IObservable& from, const IMessage& message)> f)
+    {
+      callables_[messageType] = std::set<CallableObserver*>();
+      CallableObserver* callable = new CallableObserver();
+      callable->observer = &observer;
+      callable->f = f;
+      callables_[messageType].insert(callable);
+    }
+  };
+
+
+  class MyObservable : public IObservable
+  {
+  public:
+    MyObservable(MessageBroker& broker)
+      : IObservable(broker)
+    {}
+  };
+
+  class MyObserver : public IObserver
+  {
+  public:
+    MyObserver(MessageBroker& broker)
+      : IObserver(broker)
+    {}
+    virtual void HandleMessage(IObservable& from, const IMessage& message) {}
+    void HandleSpecificMessage(IObservable& from, const IMessage& message)
+    {
+      testCounter++;
+    }
+
+  };
+
+}
+
+//#define STONE_CONNECT(observabe, messageType, observerPtr, observerMemberFnPtr)
+
+TEST(MessageBroker2, Test1)
+{
+  MessageBroker broker;
+  MyObservable  observable(broker);
+  MyObserver    observer(broker);
+
+
+  observable.Connect(MessageType_Test1, observer, boost::bind(&MyObserver::HandleSpecificMessage, &observer, _1, _2));
+  //STONE_CONNECT(observable, MessageType_Test1, observer, &MyObserver::HandleSpecificMessage)
+  observable.EmitMessage(IMessage(MessageType_Test1));
+
+  ASSERT_EQ(1, testCounter);
+}
+
+