| [084729c] | 1 | /*
 | 
|---|
 | 2 |  * Project: MoleCuilder
 | 
|---|
 | 3 |  * Description: creates and alters molecular systems
 | 
|---|
 | 4 |  * Copyright (C)  2010 University of Bonn. All rights reserved.
 | 
|---|
 | 5 |  * Please see the LICENSE file or "Copyright notice" in builder.cpp for details.
 | 
|---|
 | 6 |  */
 | 
|---|
 | 7 | 
 | 
|---|
 | 8 | /*
 | 
|---|
 | 9 |  * Observable.cpp
 | 
|---|
 | 10 |  *
 | 
|---|
 | 11 |  *  Created on: Dec 1, 2011
 | 
|---|
 | 12 |  *      Author: heber
 | 
|---|
 | 13 |  */
 | 
|---|
 | 14 | 
 | 
|---|
 | 15 | // include config.h
 | 
|---|
 | 16 | #ifdef HAVE_CONFIG_H
 | 
|---|
 | 17 | #include <config.h>
 | 
|---|
 | 18 | #endif
 | 
|---|
 | 19 | 
 | 
|---|
| [9eb71b3] | 20 | //#include "CodePatterns/MemDebug.hpp"
 | 
|---|
| [084729c] | 21 | 
 | 
|---|
 | 22 | #include "CodePatterns/Observer/Observable.hpp"
 | 
|---|
 | 23 | 
 | 
|---|
 | 24 | #include "CodePatterns/Assert.hpp"
 | 
|---|
 | 25 | #include "CodePatterns/Observer/Channels.hpp"
 | 
|---|
 | 26 | #include "CodePatterns/Observer/defs.hpp"
 | 
|---|
 | 27 | #include "CodePatterns/Observer/Notification.hpp"
 | 
|---|
 | 28 | 
 | 
|---|
 | 29 | #include <algorithm>
 | 
|---|
 | 30 | 
 | 
|---|
 | 31 | #include <boost/thread/locks.hpp>
 | 
|---|
 | 32 | #include <boost/thread/recursive_mutex.hpp>
 | 
|---|
 | 33 | 
 | 
|---|
 | 34 | //!> This function does nothing with the given Observable
 | 
|---|
 | 35 | void NoOp_informer(const Observable *)
 | 
|---|
 | 36 | {}
 | 
|---|
 | 37 | 
 | 
|---|
 | 38 | Observable::graveyard_informer_t Observable::noop_informer(&NoOp_informer);
 | 
|---|
 | 39 | 
 | 
|---|
 | 40 | Observable::ChannelMap Observable::NotificationChannels;
 | 
|---|
 | 41 | 
 | 
|---|
 | 42 | /** Attaching Sub-observables to Observables.
 | 
|---|
 | 43 |  * Increases entry in Observable::(GlobalObservableInfo::getInstance().getdepth()) for this \a *publisher by one.
 | 
|---|
 | 44 |  *
 | 
|---|
 | 45 |  * The two functions \sa start_observer_internal() and \sa finish_observer_internal()
 | 
|---|
 | 46 |  * have to be used together at all time. Never use these functions directly
 | 
|---|
 | 47 |  * START_OBSERVER and FINISH_OBSERVER also construct a bogus while(0) loop
 | 
|---|
 | 48 |  * thus producing compiler-errors whenever only one is used.
 | 
|---|
 | 49 |  * \param *publisher reference of sub-observable
 | 
|---|
 | 50 |  */
 | 
|---|
 | 51 | void Observable::start_observer_internal(Observable *publisher)
 | 
|---|
 | 52 | {
 | 
|---|
 | 53 |   boost::recursive_mutex::scoped_lock lock(GlobalObservableInfo::getInstance().getObservablesMapMutex());
 | 
|---|
 | 54 |   // increase the count for this observable by one
 | 
|---|
 | 55 |   // if no entry for this observable is found, an new one is created
 | 
|---|
 | 56 |   // by the STL and initialized to 0 (see STL documentation)
 | 
|---|
 | 57 | #ifdef LOG_OBSERVER
 | 
|---|
 | 58 |   observerLog().addMessage((GlobalObservableInfo::getInstance().getdepth())[publisher]) << ">> Locking " << observerLog().getName(publisher);
 | 
|---|
 | 59 | #endif
 | 
|---|
 | 60 |   (GlobalObservableInfo::getInstance().getdepth())[publisher]++;
 | 
|---|
 | 61 | }
 | 
|---|
 | 62 | 
 | 
|---|
 | 63 | /** Detaching Sub-observables from Observables.
 | 
|---|
 | 64 |  * Decreases entry in Observable::(GlobalObservableInfo::getInstance().getdepth()) for this \a *publisher by one. If zero, we
 | 
|---|
 | 65 |  * start notifying all our Observers.
 | 
|---|
 | 66 |  *
 | 
|---|
 | 67 |  * The two functions start_observer_internal() and finish_observer_internal()
 | 
|---|
 | 68 |  * have to be used together at all time. Never use these functions directly
 | 
|---|
 | 69 |  * START_OBSERVER and FINISH_OBSERVER also construct a bogus while(0) loop
 | 
|---|
 | 70 |  * thus producing compiler-errors whenever only one is used.
 | 
|---|
 | 71 |  * \param *publisher reference of sub-observable
 | 
|---|
 | 72 |  */
 | 
|---|
 | 73 | void Observable::finish_observer_internal(Observable *publisher)
 | 
|---|
 | 74 | {
 | 
|---|
 | 75 |   // decrease the count for this observable
 | 
|---|
 | 76 |   // if zero is reached all observed blocks are done and we can
 | 
|---|
 | 77 |   // start to notify our observers
 | 
|---|
 | 78 |   int depth_publisher = 0;
 | 
|---|
 | 79 |   {
 | 
|---|
 | 80 |     boost::recursive_mutex::scoped_lock lock(GlobalObservableInfo::getInstance().getObservablesMapMutex());
 | 
|---|
 | 81 |     --(GlobalObservableInfo::getInstance().getdepth())[publisher];
 | 
|---|
 | 82 | #ifdef LOG_OBSERVER
 | 
|---|
 | 83 |     observerLog().addMessage((GlobalObservableInfo::getInstance().getdepth())[publisher]) << "<< Unlocking " << observerLog().getName(publisher);
 | 
|---|
 | 84 | #endif
 | 
|---|
 | 85 |     depth_publisher = (GlobalObservableInfo::getInstance().getdepth())[publisher];
 | 
|---|
 | 86 |   }
 | 
|---|
 | 87 |   if(depth_publisher){}
 | 
|---|
 | 88 |   else{
 | 
|---|
 | 89 |     publisher->notifyAll();
 | 
|---|
 | 90 |     // this item is done, so we don't have to keep the count with us
 | 
|---|
 | 91 |     // save some memory by erasing it
 | 
|---|
 | 92 |     {
 | 
|---|
 | 93 |       boost::recursive_mutex::scoped_lock lock(GlobalObservableInfo::getInstance().getObservablesMapMutex());
 | 
|---|
 | 94 |       (GlobalObservableInfo::getInstance().getdepth()).erase(publisher);
 | 
|---|
 | 95 |     }
 | 
|---|
 | 96 |   }
 | 
|---|
 | 97 | }
 | 
|---|
 | 98 | 
 | 
|---|
 | 99 | void Observable::enque_notification_internal(Observable *publisher, Notification_ptr notification)
 | 
|---|
 | 100 | {
 | 
|---|
 | 101 |   boost::recursive_mutex::scoped_lock lock(GlobalObservableInfo::getInstance().getObservablesMapMutex());
 | 
|---|
 | 102 |   (GlobalObservableInfo::getInstance().getnotifications())[publisher].insert(notification);
 | 
|---|
 | 103 | }
 | 
|---|
 | 104 | 
 | 
|---|
 | 105 | /** Constructor for Observable Protector.
 | 
|---|
 | 106 |  * Basically, calls start_observer_internal(). Hence use this class instead of
 | 
|---|
 | 107 |  * calling the function directly.
 | 
|---|
 | 108 |  *
 | 
|---|
 | 109 |  * \param *protege Observable to be protected.
 | 
|---|
 | 110 |  */
 | 
|---|
 | 111 | Observable::_Observable_protector::_Observable_protector(Observable *_protege) :
 | 
|---|
 | 112 |   protege(_protege)
 | 
|---|
 | 113 | {
 | 
|---|
 | 114 |   start_observer_internal(protege);
 | 
|---|
 | 115 | }
 | 
|---|
 | 116 | 
 | 
|---|
 | 117 | Observable::_Observable_protector::_Observable_protector(const _Observable_protector &dest) :
 | 
|---|
 | 118 |     protege(dest.protege)
 | 
|---|
 | 119 | {
 | 
|---|
 | 120 |   start_observer_internal(protege);
 | 
|---|
 | 121 | }
 | 
|---|
 | 122 | 
 | 
|---|
 | 123 | /** Destructor for Observable Protector.
 | 
|---|
 | 124 |  * Basically, calls finish_observer_internal(). Hence use this class instead of
 | 
|---|
 | 125 |  * calling the function directly.
 | 
|---|
 | 126 |  *
 | 
|---|
 | 127 |  * \param *protege Observable to be protected.
 | 
|---|
 | 128 |  */
 | 
|---|
 | 129 | Observable::_Observable_protector::~_Observable_protector()
 | 
|---|
 | 130 | {
 | 
|---|
 | 131 |   finish_observer_internal(protege);
 | 
|---|
 | 132 | }
 | 
|---|
 | 133 | 
 | 
|---|
 | 134 | /************* Notification mechanism for observables **************/
 | 
|---|
 | 135 | 
 | 
|---|
 | 136 | /** Notify all Observers of changes.
 | 
|---|
 | 137 |  * Puts \a *this into Observable::(GlobalObservableInfo::getInstance().getbusyObservables()), calls Observer::update() for all in callee_t
 | 
|---|
 | 138 |  * and removes from busy list.
 | 
|---|
 | 139 |  */
 | 
|---|
 | 140 | void Observable::notifyAll() {
 | 
|---|
 | 141 | #ifdef LOG_OBSERVER
 | 
|---|
 | 142 |   observerLog().addMessage() << "--> " << observerLog().getName(this)
 | 
|---|
 | 143 |       << " is about to inform all its Observers.";
 | 
|---|
 | 144 | #endif
 | 
|---|
 | 145 |   // we are busy notifying others right now
 | 
|---|
 | 146 |   // add ourselves to the list of busy subjects to enable circle detection
 | 
|---|
 | 147 |   {
 | 
|---|
 | 148 |     boost::recursive_mutex::scoped_lock lock(GlobalObservableInfo::getInstance().getObservablesMapMutex());
 | 
|---|
 | 149 |     (GlobalObservableInfo::getInstance().getbusyObservables()).insert(this);
 | 
|---|
 | 150 |   }
 | 
|---|
 | 151 |   // see if anyone has signed up for observation
 | 
|---|
 | 152 |   // and call all observers
 | 
|---|
 | 153 |   try {
 | 
|---|
| [9ac3d3] | 154 |     bool callTable_contains;
 | 
|---|
 | 155 |     {
 | 
|---|
 | 156 |       boost::recursive_mutex::scoped_lock lock(GlobalObservableInfo::getInstance().getObservablesMapMutex());
 | 
|---|
 | 157 |       GlobalObservableInfo::calltable_t& callTable = GlobalObservableInfo::getInstance().getcallTable();
 | 
|---|
 | 158 |       callTable_contains = callTable.find(this) != callTable.end();
 | 
|---|
 | 159 |     }
 | 
|---|
| [084729c] | 160 |     if (callTable_contains) {
 | 
|---|
| [9ac3d3] | 161 |       GlobalObservableInfo::callees_t callees;
 | 
|---|
 | 162 |       {
 | 
|---|
 | 163 |         boost::recursive_mutex::scoped_lock lock(GlobalObservableInfo::getInstance().getObservablesMapMutex());
 | 
|---|
 | 164 |         GlobalObservableInfo::calltable_t& callTable = GlobalObservableInfo::getInstance().getcallTable();
 | 
|---|
 | 165 |         callees = callTable[this];
 | 
|---|
 | 166 |       }
 | 
|---|
| [084729c] | 167 |       // elements are stored sorted by keys in the multimap
 | 
|---|
 | 168 |       // so iterating over it gives us a the callees sorted by
 | 
|---|
 | 169 |       // the priorities
 | 
|---|
 | 170 |       // copy such that signOff() within receiving update() does not affect iterating
 | 
|---|
 | 171 |       // this is because within the same thread and with the updateKilled() signOff() may be
 | 
|---|
 | 172 |       // called and when executed it modifies targets
 | 
|---|
 | 173 |       GlobalObservableInfo::callees_t::iterator iter;
 | 
|---|
 | 174 |       for(iter=callees.begin();iter!=callees.end();++iter){
 | 
|---|
 | 175 | #ifdef LOG_OBSERVER
 | 
|---|
 | 176 |         observerLog().addMessage() << "-> Sending update from " << observerLog().getName(this)
 | 
|---|
 | 177 |                                    << " to " << observerLog().getName((*iter).second)
 | 
|---|
 | 178 |                                    << " (priority=" << (*iter).first << ")";
 | 
|---|
 | 179 | #endif
 | 
|---|
 | 180 |         (*iter).second->update(this);
 | 
|---|
 | 181 |       }
 | 
|---|
 | 182 |     }
 | 
|---|
 | 183 |   }
 | 
|---|
 | 184 |   ASSERT_NOCATCH("Exception thrown from Observer Update");
 | 
|---|
 | 185 | 
 | 
|---|
 | 186 |   // send out all notifications that need to be done
 | 
|---|
 | 187 |   {
 | 
|---|
| [9ac3d3] | 188 |     GlobalObservableInfo::notificationSet currentNotifications;
 | 
|---|
 | 189 |     {
 | 
|---|
 | 190 |       boost::recursive_mutex::scoped_lock lock(GlobalObservableInfo::getInstance().getObservablesMapMutex());
 | 
|---|
 | 191 |       currentNotifications = (GlobalObservableInfo::getInstance().getnotifications())[this];
 | 
|---|
 | 192 |     }
 | 
|---|
| [084729c] | 193 |     for(GlobalObservableInfo::notificationSet::iterator it = currentNotifications.begin();
 | 
|---|
 | 194 |         it != currentNotifications.end();++it){
 | 
|---|
 | 195 |       (*it)->notifyAll(this);
 | 
|---|
 | 196 |     }
 | 
|---|
 | 197 |   }
 | 
|---|
 | 198 | 
 | 
|---|
 | 199 |   {
 | 
|---|
 | 200 |     boost::recursive_mutex::scoped_lock lock(GlobalObservableInfo::getInstance().getObservablesMapMutex());
 | 
|---|
 | 201 |     (GlobalObservableInfo::getInstance().getnotifications()).erase(this);
 | 
|---|
 | 202 | 
 | 
|---|
 | 203 |      // done with notification, we can leave the set of busy subjects
 | 
|---|
 | 204 |     (GlobalObservableInfo::getInstance().getbusyObservables()).erase(this);
 | 
|---|
 | 205 |   }
 | 
|---|
 | 206 | 
 | 
|---|
 | 207 | #ifdef LOG_OBSERVER
 | 
|---|
 | 208 |   observerLog().addMessage() << "--> " << observerLog().getName(this)
 | 
|---|
 | 209 |       << " is done informing all its Observers.";
 | 
|---|
 | 210 | #endif
 | 
|---|
 | 211 | }
 | 
|---|
 | 212 | 
 | 
|---|
 | 213 | 
 | 
|---|
 | 214 | /** Handles passing on updates from sub-Observables.
 | 
|---|
 | 215 |  * Mimicks basically the Observer::update() function.
 | 
|---|
 | 216 |  *
 | 
|---|
 | 217 |  * \param *publisher The \a *this we observe.
 | 
|---|
 | 218 |  */
 | 
|---|
 | 219 | void Observable::update(Observable *publisher) {
 | 
|---|
 | 220 |   // circle detection
 | 
|---|
 | 221 |   bool presentCircle = false;
 | 
|---|
 | 222 |   {
 | 
|---|
 | 223 |     boost::recursive_mutex::scoped_lock lock(GlobalObservableInfo::getInstance().getObservablesMapMutex());
 | 
|---|
 | 224 |     presentCircle = (GlobalObservableInfo::getInstance().getbusyObservables()).find(this)!=(GlobalObservableInfo::getInstance().getbusyObservables()).end();
 | 
|---|
 | 225 |   }
 | 
|---|
 | 226 |   if(presentCircle) {
 | 
|---|
 | 227 |     // somehow a circle was introduced... we were busy notifying our
 | 
|---|
 | 228 |     // observers, but still we are called by one of our sub-Observables
 | 
|---|
 | 229 |     // we cannot be sure observation will still work at this point
 | 
|---|
 | 230 |     ASSERT(0,"Circle detected in observation-graph.\n"
 | 
|---|
 | 231 |              "Observation-graph always needs to be a DAG to work correctly!\n"
 | 
|---|
 | 232 |              "Please check your observation code and fix this!\n");
 | 
|---|
 | 233 |     return;
 | 
|---|
 | 234 |   }
 | 
|---|
 | 235 |   else {
 | 
|---|
| [9ac3d3] | 236 |     bool depth_contains;
 | 
|---|
 | 237 |     {
 | 
|---|
 | 238 |       boost::recursive_mutex::scoped_lock lock(GlobalObservableInfo::getInstance().getObservablesMapMutex());
 | 
|---|
 | 239 |       // see if we are in the process of changing ourselves
 | 
|---|
 | 240 |       // if we are changing ourselves at the same time our sub-observables change
 | 
|---|
 | 241 |       // we do not need to publish all the changes at each time we are called
 | 
|---|
 | 242 |       std::map<Observable*, int>& depth = GlobalObservableInfo::getInstance().getdepth();
 | 
|---|
 | 243 |       depth_contains = depth.find(this)==depth.end();
 | 
|---|
 | 244 |     }
 | 
|---|
| [084729c] | 245 |     if(depth_contains) {
 | 
|---|
 | 246 | #ifdef LOG_OBSERVER
 | 
|---|
 | 247 |       observerLog().addMessage() << "-* Update from " << observerLog().getName(publisher)
 | 
|---|
 | 248 |                                  << " propagated by " << observerLog().getName(this);
 | 
|---|
 | 249 | #endif
 | 
|---|
 | 250 |       notifyAll();
 | 
|---|
 | 251 |     }
 | 
|---|
 | 252 |     else{
 | 
|---|
 | 253 | #ifdef LOG_OBSERVER
 | 
|---|
 | 254 |       observerLog().addMessage() << "-| Update from " <<  observerLog().getName(publisher)
 | 
|---|
 | 255 |                                  << " not propagated by " << observerLog().getName(this);
 | 
|---|
 | 256 | #endif
 | 
|---|
 | 257 |     }
 | 
|---|
 | 258 |   }
 | 
|---|
 | 259 | }
 | 
|---|
 | 260 | 
 | 
|---|
 | 261 | /** Sign on an Observer to this Observable.
 | 
|---|
 | 262 |  * Puts \a *target into Observable::(GlobalObservableInfo::getInstance().getcallTable()) list.
 | 
|---|
 | 263 |  * \param *target Observer
 | 
|---|
 | 264 |  * \param priority number in [-20,20]
 | 
|---|
 | 265 |  */
 | 
|---|
 | 266 | void Observable::signOn(Observer *target, GlobalObservableInfo::PriorityLevel priority) const
 | 
|---|
 | 267 | {
 | 
|---|
 | 268 | #ifdef LOG_OBSERVER
 | 
|---|
 | 269 |   observerLog().addMessage() << "@@ Signing on " << observerLog().getName(target) << " to " << observerLog().getName(const_cast<Observable *>(this));
 | 
|---|
 | 270 | #endif
 | 
|---|
 | 271 |   bool res = false;
 | 
|---|
 | 272 |   boost::recursive_mutex::scoped_lock lock(GlobalObservableInfo::getInstance().getObservablesMapMutex());
 | 
|---|
 | 273 |   GlobalObservableInfo::callees_t &callees = (GlobalObservableInfo::getInstance().getcallTable())[const_cast<Observable *>(this)];
 | 
|---|
 | 274 | 
 | 
|---|
 | 275 |   GlobalObservableInfo::callees_t::iterator iter;
 | 
|---|
 | 276 |   for(iter=callees.begin();iter!=callees.end();++iter){
 | 
|---|
 | 277 |     res |= ((*iter).second == target);
 | 
|---|
 | 278 |   }
 | 
|---|
 | 279 |   if(!res)
 | 
|---|
 | 280 |     callees.insert(std::pair<int,Observer*>(priority.level,target));
 | 
|---|
 | 281 | }
 | 
|---|
 | 282 | 
 | 
|---|
 | 283 | /** Sign off an Observer from this Observable.
 | 
|---|
 | 284 |  * Removes \a *target from Observable::(GlobalObservableInfo::getInstance().getcallTable()) list.
 | 
|---|
 | 285 |  * \param *target Observer
 | 
|---|
 | 286 |  */
 | 
|---|
 | 287 | void Observable::signOff(Observer *target) const
 | 
|---|
 | 288 | {
 | 
|---|
 | 289 |   {
 | 
|---|
 | 290 |     boost::recursive_mutex::scoped_lock lock(GlobalObservableInfo::getInstance().getObservablesMapMutex());
 | 
|---|
 | 291 |     GlobalObservableInfo::calltable_t &callTable = GlobalObservableInfo::getInstance().getcallTable();
 | 
|---|
 | 292 |     ASSERT(callTable.count(const_cast<Observable *>(this)),
 | 
|---|
 | 293 |         "SignOff called for an Observable without Observers.");
 | 
|---|
 | 294 | #ifdef LOG_OBSERVER
 | 
|---|
 | 295 |     observerLog().addMessage() << "** Signing off " << observerLog().getName(target) << " from " << observerLog().getName(const_cast<Observable *>(this));
 | 
|---|
 | 296 | #endif
 | 
|---|
 | 297 |     GlobalObservableInfo::callees_t &callees = callTable[const_cast<Observable *>(this)];
 | 
|---|
 | 298 | 
 | 
|---|
 | 299 |     GlobalObservableInfo::callees_t::iterator iter;
 | 
|---|
 | 300 |     GlobalObservableInfo::callees_t::iterator deliter;
 | 
|---|
 | 301 |     for(iter=callees.begin();iter!=callees.end();) {
 | 
|---|
 | 302 |       if((*iter).second == target) {
 | 
|---|
 | 303 |         callees.erase(iter++);
 | 
|---|
 | 304 |       }
 | 
|---|
 | 305 |       else {
 | 
|---|
 | 306 |         ++iter;
 | 
|---|
 | 307 |       }
 | 
|---|
 | 308 |     }
 | 
|---|
 | 309 |     if(callees.empty()){
 | 
|---|
 | 310 |       callTable.erase(const_cast<Observable *>(this));
 | 
|---|
 | 311 |     }
 | 
|---|
 | 312 |   }
 | 
|---|
 | 313 |   (*graveyard_informer)(this);
 | 
|---|
 | 314 | }
 | 
|---|
 | 315 | 
 | 
|---|
 | 316 | void Observable::signOn(
 | 
|---|
 | 317 |     Observer *target,
 | 
|---|
 | 318 |     size_t channelno,
 | 
|---|
 | 319 |     GlobalObservableInfo::PriorityLevel priority) const
 | 
|---|
 | 320 | {
 | 
|---|
 | 321 |   Notification_ptr notification = getChannel(channelno);
 | 
|---|
 | 322 | #ifdef LOG_OBSERVER
 | 
|---|
 | 323 |   observerLog().addMessage() << "@@ Signing on " << observerLog().getName(target)
 | 
|---|
 | 324 |       << " to " << observerLog().getName(const_cast<Observable *>(this))
 | 
|---|
 | 325 |       << "'s channel no." << channelno << ".";
 | 
|---|
 | 326 | #endif
 | 
|---|
 | 327 |   notification->addObserver(target, priority.level);
 | 
|---|
 | 328 | }
 | 
|---|
 | 329 | 
 | 
|---|
 | 330 | void Observable::signOff(Observer *target, size_t channelno) const
 | 
|---|
 | 331 | {
 | 
|---|
 | 332 |   Notification_ptr notification = getChannel(channelno);
 | 
|---|
 | 333 | #ifdef LOG_OBSERVER
 | 
|---|
 | 334 |   observerLog().addMessage() << "** Signing off " << observerLog().getName(target)
 | 
|---|
 | 335 |       << " from " << observerLog().getName(const_cast<Observable *>(this))
 | 
|---|
 | 336 |       << "'s channel no." << channelno << ".";
 | 
|---|
 | 337 | #endif
 | 
|---|
 | 338 |   notification->removeObserver(target);
 | 
|---|
 | 339 |   (*graveyard_informer)(this);
 | 
|---|
 | 340 | }
 | 
|---|
 | 341 | 
 | 
|---|
 | 342 | bool Observable::isBlocked() const
 | 
|---|
 | 343 | {
 | 
|---|
 | 344 |   boost::recursive_mutex::scoped_lock lock(GlobalObservableInfo::getInstance().getObservablesMapMutex());
 | 
|---|
 | 345 |   return (GlobalObservableInfo::getInstance().getdepth()).count(const_cast<Observable *>(this)) > 0;
 | 
|---|
 | 346 | }
 | 
|---|
 | 347 | 
 | 
|---|
 | 348 | Notification_ptr Observable::getChannel(size_t no) const
 | 
|---|
 | 349 | {
 | 
|---|
 | 350 |   return getNotificationChannel(this, no);
 | 
|---|
 | 351 | }
 | 
|---|
 | 352 | 
 | 
|---|
 | 353 | size_t Observable::getNumberOfObservers() const
 | 
|---|
 | 354 | {
 | 
|---|
 | 355 |   boost::recursive_mutex::scoped_lock lock(GlobalObservableInfo::getInstance().getObservablesMapMutex());
 | 
|---|
 | 356 |   size_t ObserverCount = 0;
 | 
|---|
 | 357 |   {
 | 
|---|
 | 358 |     GlobalObservableInfo::calltable_t &callTable = GlobalObservableInfo::getInstance().getcallTable();
 | 
|---|
 | 359 |     GlobalObservableInfo::calltable_t::const_iterator callees_t_iter =
 | 
|---|
 | 360 |         callTable.find(const_cast<Observable *>(this));
 | 
|---|
 | 361 |     // if not present, then we have zero observers
 | 
|---|
 | 362 |     if (callees_t_iter != callTable.end())
 | 
|---|
 | 363 |       ObserverCount += callees_t_iter->second.size();
 | 
|---|
 | 364 |   }
 | 
|---|
 | 365 |   {
 | 
|---|
 | 366 |     boost::recursive_mutex::scoped_lock lock(GlobalObservableInfo::getInstance().getObservablesMapMutex());
 | 
|---|
 | 367 |     const Channels *OurChannels = getNotificationChannels(this);
 | 
|---|
 | 368 |     if (OurChannels != NULL)
 | 
|---|
 | 369 |       for (Channels::NotificationTypetoRefMap::const_iterator channeliter = OurChannels->ChannelMap.begin();
 | 
|---|
 | 370 |           channeliter != OurChannels->ChannelMap.end();
 | 
|---|
 | 371 |           ++channeliter)
 | 
|---|
 | 372 |         ObserverCount += (channeliter->second)->getNumberOfObservers();
 | 
|---|
 | 373 |   }
 | 
|---|
 | 374 |   return ObserverCount;
 | 
|---|
 | 375 | }
 | 
|---|
 | 376 | 
 | 
|---|
 | 377 | /** Handles sub-observables that just got killed
 | 
|---|
 | 378 |  *  when an sub-observerable dies we usually don't need to do anything
 | 
|---|
 | 379 |  *  \param *publisher Sub-Observable.
 | 
|---|
 | 380 |  */
 | 
|---|
 | 381 | void Observable::subjectKilled(Observable *publisher)
 | 
|---|
 | 382 | {
 | 
|---|
 | 383 | }
 | 
|---|
 | 384 | 
 | 
|---|
 | 385 | /** Constructor for class Observable.
 | 
|---|
 | 386 |  */
 | 
|---|
 | 387 | Observable::Observable(
 | 
|---|
 | 388 |     std::string name,
 | 
|---|
 | 389 |     const channels_t &_channels) :
 | 
|---|
 | 390 |   Observer(Observer::BaseConstructor()),
 | 
|---|
 | 391 |   graveyard_informer(&noop_informer)
 | 
|---|
 | 392 | {
 | 
|---|
 | 393 | #ifdef LOG_OBSERVER
 | 
|---|
 | 394 |   observerLog().addName(this,name);
 | 
|---|
 | 395 |   observerLog().addMessage() << "++ Creating Observable "
 | 
|---|
 | 396 |       << observerLog().getName(static_cast<Observable *>(this));
 | 
|---|
 | 397 | #endif
 | 
|---|
 | 398 | 
 | 
|---|
 | 399 |   if (!_channels.empty()) {
 | 
|---|
 | 400 |     Channels *OurChannel = new Channels;
 | 
|---|
 | 401 |     // add instance for each notification type
 | 
|---|
 | 402 |     for (channels_t::const_iterator iter = _channels.begin();
 | 
|---|
 | 403 |         iter != _channels.end(); ++iter)
 | 
|---|
 | 404 |       OurChannel->addChannel(*iter);
 | 
|---|
 | 405 |     insertNotificationChannel( std::make_pair(static_cast<Observable *>(this), OurChannel) );
 | 
|---|
 | 406 |   }
 | 
|---|
 | 407 | }
 | 
|---|
 | 408 | 
 | 
|---|
 | 409 | /** Destructor for class Observable.
 | 
|---|
 | 410 |  * When an observable is deleted, we let all our observers know. \sa Observable::subjectKilled().
 | 
|---|
 | 411 |  */
 | 
|---|
 | 412 | Observable::~Observable()
 | 
|---|
 | 413 | {
 | 
|---|
 | 414 | #ifdef LOG_OBSERVER
 | 
|---|
 | 415 |   observerLog().addMessage() << "-- Destroying Observable "
 | 
|---|
 | 416 |       << observerLog().getName(static_cast<Observable *>(this));
 | 
|---|
 | 417 | #endif
 | 
|---|
 | 418 |   bool CallTable_contains = false;
 | 
|---|
 | 419 |   {
 | 
|---|
 | 420 |     boost::recursive_mutex::scoped_lock lock(GlobalObservableInfo::getInstance().getObservablesMapMutex());
 | 
|---|
 | 421 |     CallTable_contains = (GlobalObservableInfo::getInstance().getcallTable()).count(this);
 | 
|---|
 | 422 |   }
 | 
|---|
 | 423 |   if(CallTable_contains) {
 | 
|---|
| [9ac3d3] | 424 |     GlobalObservableInfo::callees_t callees;
 | 
|---|
 | 425 |     {
 | 
|---|
 | 426 |       // copy the list from the map
 | 
|---|
 | 427 |       boost::recursive_mutex::scoped_lock lock(GlobalObservableInfo::getInstance().getObservablesMapMutex());
 | 
|---|
 | 428 |       // copy such that signOff() within receiving subjectKilled() does not affect iterating
 | 
|---|
 | 429 |       // this is because within the same thread and with the subjectKilled() signOff() may be
 | 
|---|
 | 430 |       // called and when executed it modifies targets
 | 
|---|
 | 431 |       callees = (GlobalObservableInfo::getInstance().getcallTable())[this];
 | 
|---|
 | 432 |     }
 | 
|---|
| [084729c] | 433 |     // delete all entries for this observable
 | 
|---|
 | 434 |     GlobalObservableInfo::callees_t::iterator iter;
 | 
|---|
 | 435 |     for(iter=callees.begin();iter!=callees.end();++iter)
 | 
|---|
 | 436 |       (*iter).second->subjectKilled(this);
 | 
|---|
 | 437 |     // erase the list in the map
 | 
|---|
| [9ac3d3] | 438 |     {
 | 
|---|
 | 439 |       boost::recursive_mutex::scoped_lock lock(GlobalObservableInfo::getInstance().getObservablesMapMutex());
 | 
|---|
 | 440 |       (GlobalObservableInfo::getInstance().getcallTable()).erase(this);
 | 
|---|
 | 441 |     }
 | 
|---|
| [084729c] | 442 |   }
 | 
|---|
 | 443 | 
 | 
|---|
 | 444 |   // also kill instance in static Channels map if present
 | 
|---|
 | 445 |   eraseNotificationChannel(this);
 | 
|---|
 | 446 | }
 | 
|---|
 | 447 | 
 | 
|---|
 | 448 | Observable::channels_t Observable::getChannelList(const size_t max)
 | 
|---|
 | 449 | {
 | 
|---|
 | 450 |   channels_t channels(max);
 | 
|---|
 | 451 |   std::generate(channels.begin(), channels.end(), UniqueNumber());
 | 
|---|
 | 452 |   return channels;
 | 
|---|
 | 453 | }
 | 
|---|
 | 454 | 
 | 
|---|
 | 455 | void Observable::insertNotificationChannel(std::pair<Observable*, Channels *> _pair)
 | 
|---|
 | 456 | {
 | 
|---|
 | 457 |   boost::recursive_mutex::scoped_lock lock(GlobalObservableInfo::getInstance().getObservablesMapMutex());
 | 
|---|
 | 458 |   NotificationChannels.insert(_pair);
 | 
|---|
 | 459 | }
 | 
|---|
 | 460 | 
 | 
|---|
 | 461 | void Observable::eraseNotificationChannel(Observable * const _target)
 | 
|---|
 | 462 | {
 | 
|---|
 | 463 |   boost::recursive_mutex::scoped_lock lock(GlobalObservableInfo::getInstance().getObservablesMapMutex());
 | 
|---|
 | 464 |   ChannelMap::iterator iter = NotificationChannels.find(static_cast<Observable *>(_target));
 | 
|---|
 | 465 |   if (iter != NotificationChannels.end()) {
 | 
|---|
 | 466 |     iter->second->subjectKilled(static_cast<Observable *>(_target));
 | 
|---|
 | 467 |     delete iter->second;
 | 
|---|
 | 468 |     NotificationChannels.erase(iter);
 | 
|---|
 | 469 |   }
 | 
|---|
 | 470 | }
 | 
|---|
 | 471 | 
 | 
|---|
 | 472 | bool Observable::isNotificationChannelPresent(const Observable * const _target)
 | 
|---|
 | 473 | {
 | 
|---|
 | 474 |   boost::recursive_mutex::scoped_lock lock(GlobalObservableInfo::getInstance().getObservablesMapMutex());
 | 
|---|
 | 475 |   ChannelMap::const_iterator iter =
 | 
|---|
 | 476 |       NotificationChannels.find(const_cast<Observable * const>(_target));
 | 
|---|
 | 477 |   return iter != NotificationChannels.end();
 | 
|---|
 | 478 | }
 | 
|---|
 | 479 | 
 | 
|---|
 | 480 | 
 | 
|---|
 | 481 | const Channels* Observable::getNotificationChannels(const Observable * const _target)
 | 
|---|
 | 482 | {
 | 
|---|
 | 483 |   boost::recursive_mutex::scoped_lock lock(GlobalObservableInfo::getInstance().getObservablesMapMutex());
 | 
|---|
 | 484 |   ChannelMap::const_iterator iter =
 | 
|---|
 | 485 |       NotificationChannels.find(const_cast<Observable * const>(_target));
 | 
|---|
 | 486 |   if (iter != NotificationChannels.end())
 | 
|---|
 | 487 |     return iter->second;
 | 
|---|
 | 488 |   else
 | 
|---|
 | 489 |     return NULL;
 | 
|---|
 | 490 | }
 | 
|---|
 | 491 | 
 | 
|---|
 | 492 | Notification_ptr Observable::getNotificationChannel(const Observable * const _target, const size_t _no)
 | 
|---|
 | 493 | {
 | 
|---|
 | 494 |   boost::recursive_mutex::scoped_lock lock(GlobalObservableInfo::getInstance().getObservablesMapMutex());
 | 
|---|
 | 495 |   ChannelMap::const_iterator iter =
 | 
|---|
 | 496 |       NotificationChannels.find(const_cast<Observable * const>(_target));
 | 
|---|
 | 497 |   ASSERT(iter != NotificationChannels.end(),
 | 
|---|
 | 498 |       "Observable::getNotificationChannel() - could not find channel for target "
 | 
|---|
 | 499 |       +toString(_target)+".");
 | 
|---|
 | 500 |   return iter->second->getChannel(_no);
 | 
|---|
 | 501 | }
 | 
|---|