Changeset 1c291d for src


Ignore:
Timestamp:
Mar 18, 2013, 6:29:41 PM (13 years ago)
Author:
Frederik Heber <heber@…>
Children:
3f30cc
Parents:
b9273a
git-author:
Frederik Heber <heber@…> (03/18/13 18:22:47)
git-committer:
Frederik Heber <heber@…> (03/18/13 18:29:41)
Message:

Channels and Notifications pass on subjectKilled().

  • if we only sign on to a single notification channel, we miss on subjectKilled() completely. Hence, we have to chance of properly signing off again or, at least, to know that we must not anymore.
  • Hence, Observable's dstor now calls subjectKilled() on its Channels which passes the call on to all its Notifications that in turn use the subjectKilled() slot of their targets along with the passed-through Observable instance.
  • also added observerLog verbosity when signing on/off to channels.
  • explained this in header documentation of Observable, Channels, and Notification.
  • TESTFIX: ObserverUnitTest did not properly signOff() before deleting instances in relayNotificationTest().
Location:
src
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • src/CodePatterns/Observer/Channels.hpp

    rb9273a r1c291d  
    1818#include "CodePatterns/Observer/defs.hpp"
    1919
     20class Observable;
     21class Relay;
     22
    2023/** Channels aggregate all possible Notifications of an Observable.
    2124 *
     
    2326 * visible to the outside only.
    2427 *
     28 * \note Channels::subjectKilled() needs to be called by owning Observable.
     29 * It is passed on to Notification such that Observer that have only signed
     30 * on to single channel still know when their observable has died.
    2531 */
    2632class Channels {
     
    3844
    3945private:
     46  //! grant Observable access to notifyAll() and subjectKilled()
     47  friend class Observable;
     48  //!> grant Relay access to notifyAll()
     49  friend class Relay;
     50
     51  /** Informs channel subscribers about imminent dstor call.
     52   *
     53   * This is meant to be called from Observable only.
     54   * Channels and Notifications are strictly attached to an Observable. Hence,
     55   * it makes no sense to inform them on their own. Especially, neither has
     56   * any knowledge on the publisher.
     57   *
     58   * \param *publisher Observable about to be destroyed
     59   */
     60  void subjectKilled(Observable * const publisher);
     61
     62private:
    4063  typedef std::map< size_t, Notification_ptr> NotificationTypetoRefMap;
    4164
  • src/CodePatterns/Observer/Notification.hpp

    rb9273a r1c291d  
    1616#include <set>
    1717
     18class Channels;
    1819class Observable;
    1920class Observer;
     
    2627 * with the usual OBSERVE() macro to generate both the specific and
    2728 * the global message of change.
     29 *
     30 * \note Notification::subjectKilled() needs to be called by owning Channels.
     31 * We use the passed on Observable instance to let Observers that have only
     32 * signed on to single channel know when their observable has died.
    2833 */
    2934class Notification {
    30   //!> grant Observable access to notifyAll()
    31   friend class Observable;
    32   //!> grant Relay access to notifyAll()
    33   friend class Relay;
    3435public:
    3536  Notification(size_t _channelno);
     
    4344  void removeObserver(Observer *target);
    4445
     46private:
     47  //!> grant Observable access to notifyAll() and subjectKilled()
     48  friend class Observable;
     49  //!> grant Channels access to notifyAll() and subjectKilled()
     50  friend class Channels;
     51  //!> grant Relay access to notifyAll()
     52  friend class Relay;
     53
    4554  void notifyAll(Observable * const publisher);
     55
     56  /** Informs channel subscribers about dstor call.
     57   *
     58   * This is meant to be called from Observable only.
     59   * Channels and Notifications are strictly attached to an Observable. Hence,
     60   * it makes no sense to inform them on their own. Especially, neither has
     61   * any knowledge on the publisher.
     62   *
     63   * \param *publisher Observable about to be destroyed
     64   */
     65  void subjectKilled(Observable * const publisher);
     66
    4667private:
    47   std::set<Observer*> targets;
     68  typedef std::set<Observer*> targets_t;
     69  targets_t targets;
    4870  const size_t channelno;
    4971};
  • src/CodePatterns/Observer/Observable.hpp

    rb9273a r1c291d  
    3030 * to avoid memory issues when many observable are around but only few
    3131 * are actually observed.
     32 *
     33 * \note We have to clean our Channels from static NotificationChannels and
     34 * we call Channels::subjectKilled() to let Observers that have only signed
     35 * on to single channel still know when their observable has died.
    3236 */
    3337class Observable : public Observer {
  • src/Observer/Channels.cpp

    rb9273a r1c291d  
    3434  for(NotificationTypetoRefMap::iterator iter = ChannelMap.begin();
    3535      !ChannelMap.empty(); iter = ChannelMap.begin()) {
    36     delete iter->second;
    37     ChannelMap.erase(iter);
     36    removeChannel(iter->first);
    3837  }
    3938}
     
    4140void Channels::addChannel(size_t no)
    4241{
     42#ifdef NDEBUG
    4343  NotificationTypetoRefMap::const_iterator iter = ChannelMap.find(no);
    4444  ASSERT(iter == ChannelMap.end(),
    4545      "Channels::addChannel() - channel "+toString(int(no))+" is already present in ChannelMap.");
     46#endif
    4647  ChannelMap.insert( std::make_pair(no, new Notification(no)) );
    4748}
     
    5455  delete iter->second;
    5556  ChannelMap.erase(iter);
     57}
     58
     59void Channels::subjectKilled(Observable * const publisher)
     60{
     61  for(NotificationTypetoRefMap::iterator iter = ChannelMap.begin();
     62      iter != ChannelMap.end();++iter) {
     63    iter->second->subjectKilled(publisher);
     64  }
    5665}
    5766
  • src/Observer/Notification.cpp

    rb9273a r1c291d  
    4747  }
    4848}
     49
     50void Notification::subjectKilled(Observable * const publisher)
     51{
     52  for(std::set<Observer*>::iterator it=targets.begin();
     53      it!=targets.end();++it){
     54    (*it)->subjectKilled(publisher);
     55  }
     56}
  • src/Observer/Observable.cpp

    rb9273a r1c291d  
    276276{
    277277  Notification_ptr notification = getChannel(channelno);
     278#ifdef LOG_OBSERVER
     279  observerLog().addMessage() << "@@ Signing on " << observerLog().getName(target)
     280      << " to " << observerLog().getName(const_cast<Observable *>(this))
     281      << "'s channel no." << channelno << ".";
     282#endif
    278283  notification->addObserver(target);
    279284}
     
    282287{
    283288  Notification_ptr notification = getChannel(channelno);
     289#ifdef LOG_OBSERVER
     290  observerLog().addMessage() << "** Signing off " << observerLog().getName(target)
     291      << " from " << observerLog().getName(const_cast<Observable *>(this))
     292      << "'s channel no." << channelno << ".";
     293#endif
    284294  notification->removeObserver(target);
    285295}
     
    315325#ifdef LOG_OBSERVER
    316326  observerLog().addName(this,name);
    317   observerLog().addMessage() << "++ Creating Observable " << observerLog().getName(this);
     327  observerLog().addMessage() << "++ Creating Observable "
     328      << observerLog().getName(static_cast<Observable *>(this));
    318329#endif
    319330}
     
    325336{
    326337#ifdef LOG_OBSERVER
    327   observerLog().addMessage() << "-- Destroying Observable " << observerLog().getName(this);
     338  observerLog().addMessage() << "-- Destroying Observable "
     339      << observerLog().getName(static_cast<Observable *>(this));
    328340#endif
    329341  if(callTable.count(this)) {
     
    331343    callees_t callees = callTable[this];
    332344    callees_t::iterator iter;
    333     for(iter=callees.begin();iter!=callees.end();++iter){
     345    for(iter=callees.begin();iter!=callees.end();++iter)
    334346      (*iter).second->subjectKilled(this);
    335     }
    336347    callTable.erase(this);
    337348  }
    338349
    339350  // also kill instance in static Channels map if present
    340   ChannelMap::iterator iter = NotificationChannels.find(this);
     351  ChannelMap::iterator iter = NotificationChannels.find(static_cast<Observable *>(this));
    341352  if (iter != NotificationChannels.end()) {
     353    iter->second->subjectKilled(static_cast<Observable *>(this));
    342354    delete iter->second;
    343355    NotificationChannels.erase(iter);
  • src/Observer/unittests/ObserverUnitTest.cpp

    rb9273a r1c291d  
    298298
    299299  RelayNotified->wasNotified=false;
     300  notificationObserver1->wasNotified=false;
    300301
    301302  // operation2
    302303  notificationObservable->operation2();
    303304  CPPUNIT_ASSERT(!RelayNotified->wasNotified);
    304   CPPUNIT_ASSERT(notificationObserver1->wasNotified);
     305  CPPUNIT_ASSERT(!notificationObserver1->wasNotified);
    305306
    306307  // signOff relay from 1 and operation1
     
    313314
    314315  // test kill subject
     316  RelayNotifier->signOff(RelayNotified, NotificationObservable::Operation1Notify);
    315317  delete RelayNotified;
    316318  RelayNotified = NULL; // delete in tearDown is allowed for NULL
    317319  notificationObservable->operation1();
     320  notificationObservable->signOff(RelayNotifier, NotificationObservable::Operation2Notify);
    318321  delete notificationObservable;
    319322  notificationObservable = NULL; // delete in tearDown is allowed for NULL
Note: See TracChangeset for help on using the changeset viewer.