Tulip  4.6.0
Better Visualization Through Research
library/tulip-core/include/tulip/Observable.h
00001 /*
00002  *
00003  * This file is part of Tulip (www.tulip-software.org)
00004  *
00005  * Authors: David Auber and the Tulip development Team
00006  * from LaBRI, University of Bordeaux
00007  *
00008  * Tulip is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU Lesser General Public License
00010  * as published by the Free Software Foundation, either version 3
00011  * of the License, or (at your option) any later version.
00012  *
00013  * Tulip is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00016  * See the GNU General Public License for more details.
00017  *
00018  */
00019 
00020 #ifndef OBSERVABLE_H
00021 #define OBSERVABLE_H
00022 
00023 #include <tulip/TulipException.h>
00024 #include <tulip/ForEach.h>
00025 #include <tulip/vectorgraph.h>
00026 #include <set>
00027 
00028 namespace tlp {
00029 
00030 class Observable;
00031 //=======================================
00032 /**
00033   * @ingroup Observation
00034   * @brief Event is the base class for all events used in the Observation mechanism.
00035   *
00036   * An Event is characterized by its type. The base Event class only carries information as to the type of event, nothing specific.
00037   *
00038   * Event::DELETE : send directly to all Observers/Listeners, not affected by Observable::holdObservers().
00039   * Event::MODIFICATION : sent to all Observers/Listeners. MODIFICATION are first sent to Observers and then to Listeners.
00040   * Event::INFORMATION : sent only to Listeners.
00041   * Event::INVALID : never sent, used internally for delaying events.
00042   *
00043   * @see Listener
00044   * @see Observer
00045   * @see Observable
00046   **/
00047 class  TLP_SCOPE Event {
00048   friend class Observable;
00049   friend class Graph;
00050   friend class PropertyInterface;
00051 public:
00052   enum EventType {TLP_DELETE = 0, TLP_MODIFICATION, TLP_INFORMATION, TLP_INVALID};
00053   virtual ~Event();
00054   Observable* sender() const;
00055   Event(const Observable &sender, EventType type);
00056   EventType type() const {
00057     return _type;
00058   }
00059 private:
00060   Event() {}
00061   tlp::node _sender;
00062   EventType _type;
00063 };
00064 //=======================================
00065 /**
00066  * @ingroup Observation
00067   * @class ObservableException
00068   * @brief ObservableException is the base class of all exceptions sent by the Observable/Listener/Observer system.
00069   *
00070   * @see Listener
00071   * @see Observer
00072   * @see Observable
00073   **/
00074 class  TLP_SCOPE ObservableException : public tlp::TulipException {
00075 public:
00076   ObservableException(const std::string &desc):tlp::TulipException(desc) {
00077   }
00078 };
00079 
00080 /**
00081  * @ingroup Observation
00082  * @brief The Observable class is the base of Tulip's observation system.
00083  *
00084  * Each class that wishes to send or receive notifications needs to inherit from Observable.
00085  *
00086  * Tulip has two separate mechanisms of observation, Observers and Listeners.
00087  * These two mechanisms work through the same class, the difference lies
00088  * in the way an Observer or a Listener is attached to the object whose events
00089  * it will receive.
00090  *
00091  * The Listener is closer to the original pattern, where events are sent directly to the recipient.
00092  * The Observer is a twist for performance purposes, it can receive the events in a delayed fashion, and cannot know if the event was just sent or was delayed.
00093  *
00094  * The purpose of this twist is to allow algorithms that perform a high number of modifications (e.g. creating a grid to route edges,
00095  *  creating multiple subgraphs with metrics or layouts) to run smoothly without overcrowding the event queue.
00096  * As events are sent for every graph modification (e.g. adding a node, deleting a node, setting a value on a node), the sheer quantity of events sent by these
00097  * algorithms would cause a big performance hit.
00098  *
00099  * This can be avoided by using Observable::holdObservers().
00100  * This holds all events in a queue and only sends them when Observable::unholdObservers() is called.
00101  *
00102  * The only exception to this mechanism is the Event::DELETE kind of event, that is never held back.
00103  * Think of it as an unmaskable POSIX signal; whatever the connection to the object and the state of holdObserver, this event will get through.
00104  * This is used to prevent crashes in the case where and object is listened or observed and is deleted, as it is likely the recipient
00105  * keeps a pointer to the now deleted object.
00106  *
00107  * The Listener however is not affected by the use of Observable::holdObservers() and Observable::unholdObservers().
00108  *
00109  * The observable Observers and Listeners are internally store in a Graph structure, allowing to easily visualize their connections.
00110  * This eases debugging of Observation-related bugs.
00111  *
00112  * Events are always sent to Listeners first, and then to Observers, even when there is no hold.
00113  *
00114  * If you wish to receive events, you must inherit from Observable, and implement one of two virtual functions.
00115  *
00116  * If you need to received events without delay, you will be a Listener, and need to implement treatEvent().
00117  * You will attach to the object you wish to receive events from using addListener().
00118  *
00119  * If you can receive events after a delay, you will be an Observer, and need to implement treatEvents().
00120  * You will attach to the object you wish to receive events from using addObserver().
00121  *
00122  **/
00123 class  TLP_SCOPE Observable {
00124   friend class Event;
00125 
00126 public:
00127   /**
00128   * @brief Holds back all events until Observable::unholdObservers() is called.
00129   *
00130   * Listeners are not affected by this function.
00131   * Once this function is called, all events heading to an Observer will be held, except DELETE events.
00132   * The events are stored in a queue, and will be sent once Observable::unholdObservers() is called.
00133   *
00134   * It is possible to nest calls to  Observable::holdObservers() and  Observable::unholdObservers(),
00135   * and in this case the events will only be sent when there
00136   * have been as many calls to  Observable::unholdObservers() as to  Observable::holdObservers().
00137   *
00138   * It is possible to check whether the events are being help by checking the Observable::observersHoldCounter() function.
00139   *
00140   * @see unholdObservers
00141   * @see observersHoldCounter
00142   */
00143   static void holdObservers();
00144   /**
00145   * @brief Sends all held events to the Observers.
00146   *
00147   * Listeners are not affected by this function.
00148   *
00149   * In debug mode, if the hold counter is less than one when calling this function, an ObservableException will be raised.
00150   *
00151   * @see holdObservers
00152   * @see observersHoldCounter
00153   */
00154   static void unholdObservers();
00155 
00156   /**
00157    * @brief observersHoldCounter gives the number of times holdObservers() has been called without a matching unholdObservers() call.
00158    * @return the number of times holdObservers() has been called without a matching unholdObservers() call.
00159    */
00160   static unsigned int observersHoldCounter() {
00161     return _oHoldCounter;
00162   }
00163 
00164   /**
00165    * @brief Adds an Observer to this object.
00166    *
00167    * The observer will receive events sent by this object, if there is no hold applied.
00168    * @param observer The object that will receive events.
00169    */
00170   void addObserver(Observable * const observer) const;
00171 
00172   /**
00173    * @brief Adds a Listener to this object.
00174    *
00175    * The Listener will receive events regardless of the state of holdObservers() and unholdObservers().
00176    * @param listener The object that will receive events.
00177    */
00178   void addListener(Observable * const listener) const;
00179 
00180   /**
00181    * @brief Removes an observer from this object.
00182    *
00183    * The observer will no longer receive events from this object.
00184    * @param observer The observer to remove from this object.
00185    */
00186   void  removeObserver(Observable  * const observerver) const;
00187 
00188   /**
00189    * @brief Removes a listener from this object.
00190    *
00191    * The listener will no longer receive events from this object.
00192    * @param listener The listener to remove from this object.
00193    */
00194   void  removeListener(Observable  * const listener) const;
00195 
00196   /**
00197    * @brief gets the number of sent events.
00198    * @return the number of sent events (0 when compiling with -DNDEBUG).
00199    */
00200   unsigned int getSent() const;
00201   \
00202   /**
00203    * @brief get the number of received events.
00204    * @return the number of received events (0 when compiling with -DNDEBUG).
00205    */
00206   unsigned int getReceived() const;
00207 
00208   /**
00209    * @brief gets the number of observers attached to this object.
00210    * @return the number of observers attached to this object.
00211    */
00212   unsigned int countObservers() const;
00213 
00214   /**
00215    * @brief gets the number of listeners attached to this object.
00216    * @return the number of listeners attached to this object.
00217    */
00218   unsigned int countListeners() const;
00219 
00220 public:
00221   /**
00222    * @brief internal function for debugging purpose
00223    * If there is no hold currently applied, or no update ongoing, always returns true.
00224    * Checks if the object represented by the node has been deleted.
00225    * @param n The node to check for life signs.
00226    * @return Whether the node is dead.
00227   **/
00228   static bool isAlive(tlp::node n);
00229 
00230   /**
00231    * @brief internal function for debugging purpose
00232    * If called during an update, it is possible the pointed object has been deleted.
00233    * use isAlive() to check for this and avoid a crash.
00234    * @param n The node representing the object to retrieve.
00235    * @return The object represented by the node.
00236   **/
00237   static Observable* getObject(tlp::node n);
00238 
00239   /**
00240    * @brief internal function for debugging purpose
00241    * getScheduled get the number of scheduled events for this Observable.
00242    * @param n The node of an Observable object
00243    * @return the number of scheduled events involving this Observable as sender or receiver.
00244    */
00245   static unsigned int getScheduled(tlp::node n);
00246 
00247   /**
00248    * @brief internal function for debugging purpose
00249    * Get the node representing this object in the Observable Graph.
00250    * @param obs the Observable object
00251    * @return the node of the Observable object in the Observable Graph.
00252    */
00253   static tlp::node getNode(const tlp::Observable* obs);
00254 
00255   /**
00256    * @brief Gets the observation graph.
00257    * @return The graph containing a node for each Observable/Observer/Listener, and an edge between connected objects.
00258    */
00259   static const tlp::VectorGraph& getObservableGraph();
00260 
00261 protected:
00262   Observable();
00263   Observable(const Observable &);
00264   virtual ~Observable();
00265   Observable& operator=(const Observable &);
00266 
00267   /**
00268    * @brief Sends an event to all the Observers/Listeners.
00269    * It is higly recommended to check if there are observers/listeners to send the event to before actually sending it
00270    * to avoid the overhead of creating too many objects.
00271    *
00272    * This can be achieved by using the hasOnLookers() function :
00273    *
00274    * @code
00275    *    if (hasOnlookers()) {
00276    *       sendEvent(GraphEvent(*this, GraphEvent::TLP_ADD_NODE, n));
00277    *    }
00278    * @endcode
00279    *
00280    * @param message The message to send to the listeners/observers.
00281    */
00282   void sendEvent(const Event &message);
00283 
00284   /**
00285    * @brief This function is called when events are sent to Observers, and Observers only.
00286    *
00287    * It is passed a vector of all the events that happened since the last call.
00288    * If events were held, this vector can be pretty large, and if events were not held it is likely it only contains a single element.
00289    *
00290    * @param events The events that happened since the last unHoldObservers().
00291    */
00292   virtual void treatEvents(const std::vector<Event> &events);
00293 
00294   /**
00295    * @brief This function is called when events are sent to the Listeners, and Listeners only.
00296    *
00297    * Is it passed a reference to the event that just happened.
00298    *
00299    * @param message The event that was sent.
00300    */
00301   virtual void treatEvent(const Event &message);
00302 
00303   /**
00304   * @brief Sends the Event::DELETE before the deletion of the subclass and its internal objects.
00305   *
00306   * The observation system automatically sends the DELETE event when the Observable is deleted, but
00307   * in the case you need to access members of the class inheriting from Observable, you need the event
00308   * sent *before* the outermost objects are destroyed.
00309   *
00310   * To achieve this, you can call this function in your destructor, and the DELETE event will be sent.
00311   * This will allow your Listeners/Observers to access your members one last time before deletion.
00312   *
00313   * @warning This function must be called only once per object.
00314   * Make sure no other class in the inheritance tree calls this function before adding this call to your destructor.
00315   */
00316   void observableDeleted();
00317 
00318   /**
00319    * @brief Checks whether there are Observers/Listeners attached to this object.
00320    *
00321    * Using this function avoids the creation of events that no-one will see :
00322    * @code
00323    *    if (hasOnlookers()) {
00324    *       sendEvent(GraphEvent(*this, GraphEvent::TLP_ADD_NODE, n));
00325    *    }
00326    * @endcode
00327    *
00328    * @return
00329    */
00330   bool hasOnlookers() const;
00331 
00332   /**
00333   * @brief use for old observer tulip compatibility
00334   */
00335   _DEPRECATED  tlp::Iterator<tlp::Observable *> * getObservables() const;
00336 
00337   /**
00338   * @brief use for old observer tulip compatibility
00339   */
00340   _DEPRECATED void notifyObservers();
00341 
00342 private:
00343   enum OBSERVABLEEDGETYPE {OBSERVABLE = 0x01, OBSERVER = 0x02, LISTENER = 0x04};
00344 
00345   /**
00346    * @brief deleteMsgSent This allows for calling observableDeleted() multiple times safely.
00347    */
00348   bool deleteMsgSent;
00349 
00350   /**
00351    * @brief queuedEvent Used to prevent unecessary elements insertion in the set of events.
00352    */
00353   mutable bool queuedEvent;
00354 
00355   /**
00356    * @brief _n The node that represents this object in the ObservableGraph.
00357    */
00358   tlp::node _n;
00359 #ifndef NDEBUG
00360   /**
00361    * @brief sent The number of sent events
00362    */
00363   unsigned int sent;
00364 
00365   /**
00366    * @brief received The number of received events.
00367    */
00368   unsigned int received;
00369 #endif
00370 
00371   /**
00372   * @brief return an Iterator on all Onlookers
00373   * @warning adding or removing Onlooker to that Observable will devalidate the iterator
00374   * @see StableIterator
00375   * @see forEach
00376   * @see stableForEach
00377   */
00378   tlp::Iterator<Observable *> *getOnlookers() const;
00379 
00380   /**
00381    * @brief getInObjects Retrieves Inbound objects (observed objects; i.e. Observable).
00382    * @return an iterator on 'in' objects (Observable), the iterator guarantees that all objects are alive (not deleted during hold or notify).
00383    */
00384   tlp::Iterator<tlp::node> *getInObjects() const;
00385 
00386   /**
00387    * @brief getOutObjects Retrieves Outbound objects (observing objects; i.e. Listeners and Observers).
00388    * @return an iterator on out objects (Listener/Observer), the iterator garantees that all objects are alive (not deleted during hold or notify).
00389    */
00390   tlp::Iterator<tlp::node> *getOutObjects() const;
00391 
00392   /**
00393    * @brief addOnlooker Adds an Observer/Listener to this object.
00394    *
00395    * The added Onlookers will received the next Event sent by the Observable.
00396    * In case of nested unholding (higly unlikely), calling that function inside hold/unhold block
00397    * can make the Observer receive an event that has been sent before it was Observing the object.
00398    *
00399    * @param obs The Observer/Listener to add to this object.
00400    * @param type The kind of observation (Listener or Observer).
00401    */
00402   void addOnlooker(const Observable &obs, OBSERVABLEEDGETYPE type) const;
00403 
00404   /**
00405    * @brief removeOnlooker removes an Observer/Listener from this object.
00406    *
00407    * In case of nested unholding (higly unlikely), calling that function inside a hold/unhold block could
00408    * make the Observer not receive an event that was sent when it was connected.
00409    *
00410    * @warning removing OnLooker that has been created outside of your code can create serious
00411    * problems in your application. Objects that are listening/observing could need to receive
00412    * the events to work properly.
00413    *
00414    * @param obs The Observer/Listener to remove
00415    * @param type The kind of connection (Listener or Observer).
00416    */
00417   void removeOnlooker(const Observable &obs, OBSERVABLEEDGETYPE type) const;
00418 
00419   /**
00420    * @brief getNode Get the node representing this object in the ObservableGraph.
00421    * @return the node representing that ObservableObject in the ObservableGraph.
00422    */
00423   tlp::node getNode() const;
00424 
00425   //static members and methods
00426   /**
00427    * @brief _oGraph the graph used to store all observers and connection between them.
00428    */
00429   static tlp::VectorGraph _oGraph;
00430 
00431   /**
00432    * @brief _oPointer a pointer to the object represented by a node
00433    */
00434   static tlp::NodeProperty<Observable *> _oPointer;
00435 
00436   /**
00437    * @brief _oAlive whether an object has been deleted or not
00438    */
00439   static tlp::NodeProperty<bool> _oAlive;
00440 
00441   /**
00442    * @brief _oEventsToTreat the count of events scheduled to be treated by an object
00443    * the object's associated node is deleted only when this count is null
00444    * in order to prevent the node reuse and ensure the _oAlive associated value
00445    */
00446   static tlp::NodeProperty<unsigned int> _oEventsToTreat;
00447 
00448   /**
00449    * @brief _oType the type of relation between two Observable Objects
00450    */
00451   static tlp::EdgeProperty<unsigned char> _oType;
00452 
00453   /**
00454    * @brief _oDelayedDelNode store deleted nodes, to remove them at the end of the notify
00455    */
00456   static std::vector<tlp::node> _oDelayedDelNode;
00457 
00458   static std::set<std::pair<tlp::node, tlp::node> > _oDelayedEvents;
00459 
00460   /**
00461    * @brief _oNotifying counter of nested notify calls
00462    */
00463   static unsigned int _oNotifying;
00464 
00465   /**
00466    * @brief _oUnholding counter of nested unhold calls
00467    */
00468   static unsigned int _oUnholding;
00469 
00470   /**
00471    * @brief _oHoldCounter counter of nested holds
00472    */
00473   static unsigned int _oHoldCounter;
00474 
00475   /**
00476    * @brief _oInitialized use to initialize oGraph when the library is loaded (nice hack)
00477    */
00478   static bool _oInitialized;
00479 
00480   /**
00481   * @brief delete nodes from the ObservableGraph that have been preserved to keep coherency and check bad use of the mechanism.
00482   */
00483   static void updateObserverGraph();
00484 
00485   /**
00486    * @brief getBoundNode
00487    * @return the bound node representing this ObservableObject in the ObservableGraph,
00488    * if _n is not valid it is then bound to a new added node
00489    */
00490   tlp::node getBoundNode();
00491   bool isBound() const {
00492     return _n.isValid();
00493   }
00494 
00495   /**
00496   * @brief Trick to init the ObservableGraph properties (called at the loading of the library, during static initialization).
00497   */
00498   static bool init();
00499 };
00500 
00501 /**
00502  * @brief The ObserverHolder class is a convenience class to automatically hold and unhold observers.
00503  * It performs a call to Observable::holdObserver() at its creation and a call to Observable::unholdObserver() at its destruction.
00504  * You can use it if you have to hold observers in a function with multiple return points to avoid to call Observable::unholdObserver() for each of them.
00505  * @code
00506  * void myFunc(){
00507  *  ObserverHolder holder;//Automatically call Observable::holdObserver()
00508  *
00509  *  if(someTest()){
00510  *      someOperation1();
00511  *      return;//No need to call Observable::unholdObserver() it will be called with the destruction of the locker object
00512  *  }
00513  *
00514  * }
00515  * @endcode
00516  *
00517  */
00518 class TLP_SCOPE ObserverHolder {
00519 public :
00520   ObserverHolder() {
00521     Observable::holdObservers();
00522   }
00523   ~ObserverHolder() {
00524     Observable::unholdObservers();
00525   }
00526 };
00527 
00528 // deprecated name of this class
00529 _DEPRECATED_TYPEDEF(ObserverHolder, ObserverLocker);
00530 
00531 }
00532 
00533 #endif
 All Classes Files Functions Variables Enumerations Enumerator Properties