// // This file is part of the aMule Project. // // Copyright (c) 2005-2011 Mikkel Schubert ( xaignar@users.sourceforge.net ) // Copyright (c) 2005-2011 aMule Team ( admin@amule.org / http://www.amule.org ) // // Any parts of this program derived from the xMule, lMule or eMule project, // or contributed by third-party developers are copyrighted by their // respective authors. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA // #ifndef OBSERVABLE_H #define OBSERVABLE_H #include #include "OtherFunctions.h" // Needed for CMutexUnlocker template class CObservable; /** * This class implements the observable part of an Observer/Observable pattern. * * The EventType paramter is used to specify a protocol for the event-type used * by a particular Observer/Observable set and allows for any level of * information passing to be used, depending on the context. * * In order to simplify matters for subclasses, both the Observer and the * Observable class keep track of which objects are observing what, so that * instances can safely be created and destroyed without having to manually * keep the observers and observables in sync. */ template class CObserver { friend class CObservable; public: typedef CObservable ObservableType; /** * Destructor. * * All observables which has this object registered are notified * as to avoid dangling pointers. This will not result in actual * events. */ virtual ~CObserver(); protected: /** * This function is called when an observed subject publishes an event. * * @param o The publisher of the event. * @param e The actual event. */ virtual void ReceiveNotification( const ObservableType* o, const EventType& e ) = 0; private: //! Mutex used to make access to the list of observed objects thread safe. wxMutex m_mutex; typedef std::set ObservableSetType; //! List of objects being observed. ObservableSetType m_list; }; /** * This class implements the Observable part of the Observer/Observable pattern. */ template class CObservable { friend class CObserver; public: //! The observer-type accepted by this class typedef CObserver ObserverType; /** * Destructor. */ virtual ~CObservable(); /** * This function subscribes an observer to events from this observable. * * @param o The observer that wishes to observe this object. * @return True if it succesfully subscribed, false otherwise. * * If the subscription was succesful, ObserverAdded() will be called * on "o", allowing the subclass to initialize the the observer's state. */ bool AddObserver( ObserverType* o ); /** * This function removes an observer from the list of subscribers. * * @param o The observer to unsubscribe from this observable. * @return True if the observer was removed, false otherwise. * * ObserverRemoved() will be called for the observer "o", allowing * the subclass to take steps to avoid outdated data being kept. */ bool RemoveObserver( ObserverType* o ); protected: /** * This function notifies all or an specific observer of an event. * * @param e The event to be published. * @param o A specific subscribing observer or NULL for all subscribers. * * The purpose of the second parameter is to allow notifications of * specific observers when the ObserverAdded() or ObserverRemoved() * functions are called and it should not be used outside of these * functions. */ void NotifyObservers( const EventType& e, ObserverType* o = NULL ); /** * This function removes all observers from this object. * * ObserverRemoved is called on each observer. */ void RemoveAllObservers(); /** * This function is called when an observer has been added to the observable. */ virtual void ObserverAdded( ObserverType* ) {}; /** * This function is called when observers are removed from the observable. * * Exceptions to this are: * - When the Observable is being destroyed. * - When the Observer is being destroyed. */ virtual void ObserverRemoved( ObserverType* ) {}; private: //! Mutex used to ensure thread-safety of the basic operations. wxMutex m_mutex; typedef std::set ObserverSetType; typedef typename ObserverSetType::iterator myIteratorType; //! Set of all observers subscribing to this observable. ObserverSetType m_list; }; /////////////////////////////////////////////////////////////////////////////// template CObserver::~CObserver() { wxMutexLocker lock( m_mutex ); while ( !m_list.empty() ) { ObservableType* o = *m_list.begin(); { wxMutexLocker oLock(o->m_mutex); o->m_list.erase( this ); } m_list.erase( m_list.begin() ); } } template CObservable::~CObservable() { wxMutexLocker lock( m_mutex ); while ( !m_list.empty() ) { ObserverType* o = *m_list.begin(); { wxMutexLocker oLock(o->m_mutex); o->m_list.erase( this ); } m_list.erase( m_list.begin() ); } } template bool CObservable::AddObserver( CObserver* o ) { wxASSERT( o ); { wxMutexLocker lock(m_mutex); if ( !m_list.insert( o ).second ) { return false; } } { wxMutexLocker oLock(o->m_mutex); o->m_list.insert( this ); } ObserverAdded( o ); return true; } template bool CObservable::RemoveObserver( CObserver* o ) { wxASSERT( o ); { wxMutexLocker lock(m_mutex); if ( !m_list.erase( o ) ) { return false; } } { wxMutexLocker oLock(o->m_mutex); o->m_list.erase( this ); } ObserverRemoved( o ); return true; } template void CObservable::NotifyObservers( const EventType& e, ObserverType* o ) { wxMutexLocker lock(m_mutex); if ( o ) { o->ReceiveNotification( this, e ); } else { myIteratorType it = m_list.begin(); for ( ; it != m_list.end(); ) { CMutexUnlocker unlocker(m_mutex); (*it++)->ReceiveNotification( this, e ); } } } template void CObservable::RemoveAllObservers() { wxMutexLocker lock(m_mutex); while ( !m_list.empty() ) { ObserverType* o = *m_list.begin(); m_list.erase( m_list.begin() ); CMutexUnlocker unlocker(m_mutex); { wxMutexLocker oLock(o->m_mutex); o->m_list.erase( this ); } ObserverRemoved( o ); } } #endif // File_checked_for_headers