/* * 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" /** Constructor for class Relay. */ Relay::Relay(string name) : Observer(Observer::BaseConstructor()) { #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 if(callTable.count(this)) { // delete all entries for this observable callees_t callees = callTable[this]; callees_t::iterator iter; for(iter=callees.begin();iter!=callees.end();++iter){ (*iter).second->subjectKilled(this); } callTable.erase(this); } } /** Notify all Observers of changes. * Puts \a *this into Relay::busyRelays, calls Observer::update() for all in callee_t * and removes from busy list. */ void Relay::notifyAll() { // we are busy notifying others right now // add ourselves to the list of busy subjects to enable circle detection busyRelays.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[this]; for(notificationSet::iterator it = currentNotifications.begin(); it != currentNotifications.end();++it){ (*it)->notifyAll(); } notifications.erase(this); // done with notification, we can leave the set of busy subjects busyRelays.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(busyRelays.find(this)!=busyRelays.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) << endl; #endif Updater = publisher; notifyAll(); } else{ #ifdef LOG_OBSERVER observerLog().addMessage() << "-| Update from " << observerLog().getName(publisher) << " not relayed by " << observerLog().getName(this) << endl; #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){ }