/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2010 University of Bonn. All rights reserved. * Please see the LICENSE file or "Copyright notice" in builder.cpp for details. */ /* * Relay.cpp * * Created on: Dec 1, 2011 * Author: heber */ // include config.h #ifdef HAVE_CONFIG_H #include #endif #include "MemDebug.hpp" #include "Relay.hpp" #include "Assert.hpp" #include "Channels.hpp" #include "defs.hpp" #include "Notification.hpp" /** Constructor for class Relay. */ Relay::Relay(std::string name) : Observable(name), Updater(NULL) { #ifdef LOG_OBSERVER observerLog().addName(this,name); observerLog().addMessage() << "++ Creating Relay " << observerLog().getName(this); #endif } /** Destructor for class Relay. * When an observable is deleted, we let all our observers know. \sa Relay::subjectKilled(). */ Relay::~Relay() { #ifdef LOG_OBSERVER observerLog().addMessage() << "-- Destroying Relay " << observerLog().getName(this); #endif } /** Notify all Observers of changes. * Puts \a *this into Relay::busyObservables, calls Observer::update() for all in callee_t * and removes from busy list. */ void Relay::notifyAll() { ASSERT(Updater != NULL, "Relay::notifyAll() called while Updater is NULL."); // we are busy notifying others right now // add ourselves to the list of busy subjects to enable circle detection busyObservables.insert(this); // see if anyone has signed up for observation // and call all observers try { if(callTable.count(this)) { // elements are stored sorted by keys in the multimap // so iterating over it gives us a the callees sorted by // the priorities callees_t callees = callTable[this]; callees_t::iterator iter; for(iter=callees.begin();iter!=callees.end();++iter){ #ifdef LOG_OBSERVER observerLog().addMessage() << "-> " << observerLog().getName(this) << " is relaying update from " << observerLog().getName(Updater) << " to " << observerLog().getName((*iter).second) << " (priority=" << (*iter).first << ")"; #endif (*iter).second->update(Updater); } } } ASSERT_NOCATCH("Exception thrown from Observer Update"); // send out all notifications that need to be done notificationSet currentNotifications = notifications[Updater]; for(notificationSet::iterator it = currentNotifications.begin(); it != currentNotifications.end();++it){ (*it)->notifyAll(Updater); } notifications.erase(Updater); // done with notification, we can leave the set of busy subjects busyObservables.erase(this); } /** Handles passing on updates from sub-Relays. * Mimicks basically the Observer::update() function. * * \param *publisher The \a *this we observe. */ void Relay::update(Observable *publisher) { // circle detection if(busyObservables.find(this)!=busyObservables.end()) { // somehow a circle was introduced... we were busy notifying our // observers, but still we are called by one of our sub-Relays // we cannot be sure observation will still work at this point ASSERT(0,"Circle detected in observation-graph.\n" "Observation-graph always needs to be a DAG to work correctly!\n" "Please check your observation code and fix this!\n"); return; } else { // see if we are in the process of changing ourselves // if we are changing ourselves at the same time our sub-observables change // we do not need to publish all the changes at each time we are called if(depth.find(this)==depth.end()) { #ifdef LOG_OBSERVER observerLog().addMessage() << "-* Update from " << observerLog().getName(publisher) << " relayed by " << observerLog().getName(this); #endif Updater = publisher; notifyAll(); } else{ #ifdef LOG_OBSERVER observerLog().addMessage() << "-| Update from " << observerLog().getName(publisher) << " not relayed by " << observerLog().getName(this); #endif } } } //Notification_ptr Relay::getChannel(size_t no) const //{ // ASSERT(NotificationChannels != NULL, // "Relay::getChannel() - observable has no channels."); // return NotificationChannels->getChannel(no); //} /** Handles sub-observables that just got killed * when an sub-observerable dies we usually don't need to do anything * \param *publisher Sub-Relay. */ void Relay::subjectKilled(Observable *publisher){ }