Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members   Related Pages  

EventSender.cc

Go to the documentation of this file.
00001 #ifndef EVENT_SENDER_CC_TEMPLATE
00002 #define EVENT_SENDER_CC_TEMPLATE
00003 
00022 #include <algorithm>
00023 #include "EventSender.hh"
00024 
00025 namespace 
00026 {
00028     enum DEBUG_LEVELS {NO_DEBUG = 1, DEBUG_VERBOSE = 2};
00031     const DEBUG_LEVELS DEBUG_LEVEL = NO_DEBUG;
00032 }
00033 
00040 template <typename EvType> 
00041 EventSender<EvType>& 
00042 EventSender<EvType>::instance() 
00043 {
00044     static EventSender<EvType> eventSender;
00045     return eventSender;
00046 }
00047 
00049 template <typename EvType>
00050 void
00051 EventSender<EvType>::sendEvent(const EvType& event) 
00052 {
00053     /*
00054         If isBusySending == true, then problem: an attempt 
00055         is being made to send an EvType while one is already 
00056         being sent to listeners. Since the same listeners will be
00057         called again with the new event, this could lead to an 
00058         infinite loop.
00059     */
00060     if (_isBusySending) 
00061         throw IllegalSendError();
00062     
00063     // nothing else to do if no listeners registered
00064     if (_registry.empty())
00065     {
00066         if (DEBUG_LEVEL >= DEBUG_VERBOSE)
00067             std::cout << "No " << lisnrID() 
00068                       << " registered." << std::endl;
00069         return;
00070     }
00071     
00072     assert(!_isBusySending);
00073     _isBusySending = true;
00074     _eventIgnored = 0; // reset the event-ignored counter
00075     
00076     // Send event to each listener currently in registry
00077     typename Registry::iterator registryIter = _registry.begin();
00078     for (typename Registry::iterator registryIter = _registry.begin();
00079          registryIter != _registry.end(); ++ registryIter) 
00080     {
00081         if (DEBUG_LEVEL >= DEBUG_VERBOSE)
00082             std::cout << "Calling "  << lisnrID(*registryIter)
00083                       << "::processEventPublic"  << std::endl;
00084 
00085         try 
00086         { 
00087             (*registryIter)->processEventPublic(event); 
00088         }
00089         catch (const IllegalSendError&)
00090         {
00091             // propagate recursive flushes up the stack
00092             _isBusySending = false;
00093             cleanupQueues();
00094             throw;
00095         }
00096         catch (const std::exception& e)
00097         {
00098             std::cerr 
00099                 << "*** BUG Alert: " << lisnrID(*registryIter) 
00100                 << "::processEvent()\n    threw an EXCEPTION of type " 
00101                 << typeid(e).name() 
00102                 << ".\n    The processEvent() must NOT leak ANY exception."
00103                 << "  Message is:\n" << e.what() << "\n\n";
00104         }
00105         catch (...) 
00106         {
00107             std::cerr 
00108                << "*** BUG Alert: " << lisnrID(*registryIter) 
00109                << "::processEvent() threw an EXCEPTION" 
00110                << "\n    of UNKNOWN type (not derived from std::exception)."
00111                << "\n    The processEvent() must NOT leak ANY exception." 
00112                << "\n\n";
00113         }
00114     }
00115     
00116     _isBusySending = false;
00117     // hold promise: the registration queue must 
00118     // be empty when isBusySending is over
00119     cleanupQueues();
00120 }
00121 
00125 template<typename EvType>
00126 EventSender<EvType>::~EventSender()
00127 {
00128     // doesn't make sense to have EventSender destroyed while sending
00129     assert(!_isBusySending);
00130     // deregister every listener
00131     while (! _registry.empty()) 
00132     {
00133         _registry.front()->TListener::ignoreEvents();
00134     }
00135 }
00136 
00141 template<typename EvType>
00142 void
00143 EventSender<EvType>::cleanupQueues()
00144 {
00145     assert(_isBusySending == false);
00146     
00147     // register listeners that have been queued for registration
00148     while (! _registrationQueue.empty()) 
00149     {
00150         typename Registry::iterator registryIter = _registrationQueue.begin();
00151         if (DEBUG_LEVEL >= DEBUG_VERBOSE)
00152             std::cout << "Registering queued " << lisnrID(*registryIter) 
00153                       << std::endl;
00154         // splice node from registration queue to registry
00155         _registry.splice(_registry.end(), _registrationQueue, registryIter);
00156         // make sure no other copy left in queue
00157         assert(std::find(_registrationQueue.begin(), 
00158                          _registrationQueue.end(), _registry.back()) 
00159                == _registrationQueue.end());
00160     }
00161     
00162     // remove listeners that have been queued for removal
00163     while (! _removalQueue.empty()) 
00164     {
00165         TListener* lisnr = _removalQueue.back();
00166         if (DEBUG_LEVEL >= DEBUG_VERBOSE)
00167             std::cout << "Removing queued " << lisnrID(lisnr) << std::endl;
00168         
00169         if (! removeFrom(_registry, lisnr) 
00170             && DEBUG_LEVEL >= DEBUG_VERBOSE)
00171             std::cout << "Listener " << lisnrID(lisnr)
00172                       << " not in registry, removal ignored" << std::endl;
00173         _removalQueue.pop_back();
00174     }
00175 }
00176 
00181 template<typename EvType>
00182 bool 
00183 EventSender<EvType>::removeFrom(Registry& container, TListener* lisnr)
00184 {
00185     // Find iterator for listener to be removed
00186     typename Registry::iterator removeIter
00187         = std::find(container.begin(), container.end(), lisnr);
00188     if ( removeIter != container.end() ) 
00189     {
00190         container.erase(removeIter);
00191         if (DEBUG_LEVEL >= DEBUG_VERBOSE)
00192             std::cout << lisnrID(lisnr) << " removed from list" 
00193                       << std::endl;
00194         return true;
00195     }
00196     
00197     // listener not found anywhere
00198     if (DEBUG_LEVEL >= DEBUG_VERBOSE)
00199         std::cout << lisnrID(lisnr) << " NOT found in list" 
00200                   << std::endl;
00201     return false;
00202 }
00203 
00215 template<typename EvType>
00216 void 
00217 EventSender<EvType>::removeListener(TListener* lisnr)
00218 {
00219     if (_isBusySending)
00220     {
00221         if (! removeFrom(_registrationQueue, lisnr))
00222         {
00223             assert(std::find(_removalQueue.begin(), 
00224                    _removalQueue.end(), lisnr) == _removalQueue.end());
00225             _removalQueue.push_back(lisnr);
00226 
00227             if (DEBUG_LEVEL >= DEBUG_VERBOSE)
00228                 std::cout << "Putting " << lisnrID(lisnr) 
00229                           << " on removal queue" << std::endl;
00230         }
00231         else // nothing to do, already removed from registration queue
00232         {
00233             if (DEBUG_LEVEL >= DEBUG_VERBOSE)
00234                 std::cout << lisnrID(lisnr) 
00235                           << " removed from registration queue" 
00236                           << std::endl;
00237         }
00238     }
00239     else
00240     {
00241         assert(_removalQueue.empty());
00242         assert(_registrationQueue.empty());
00243         const bool removed = removeFrom(_registry, lisnr);
00244         assert(removed);
00245     }
00246 }
00247 
00259 template<typename EvType>
00260 void 
00261 EventSender<EvType>::registerListener(TListener* lisnr)
00262 {
00263     if (_isBusySending)
00264     // use queues instead
00265     {
00266         // first see if it is on the removal queue
00267         if (! removeFrom(_removalQueue, lisnr))
00268         {
00269             // wasn't in removal queue, so put on registration queue
00270             // note that it shouldn't be possible to have listener 
00271             // register itself if it is already in the queue or registered
00272             assert(std::find(_registrationQueue.begin(), 
00273                    _registrationQueue.end(), lisnr) == _registrationQueue.end());
00274             _registrationQueue.push_back(lisnr);
00275             if (DEBUG_LEVEL >= DEBUG_VERBOSE)
00276                 std::cout << "Putting " << lisnrID(lisnr) 
00277                           << " on registration queue" << std::endl;
00278         }
00279         else // nothing to do, already in queue
00280         {
00281             if (DEBUG_LEVEL >= DEBUG_VERBOSE)
00282                 std::cout << lisnrID(lisnr) 
00283                           << " removed from registration queue" 
00284                           << std::endl;
00285         }
00286     }
00287     else // safe to register immediately
00288     {
00289         // this method never called if already registerd, so assert this:
00290         assert(std::find(_registry.begin(), _registry.end(), lisnr)
00291                 == _registry.end());
00292         
00293         _registry.push_back(lisnr);
00294         if (DEBUG_LEVEL >= DEBUG_VERBOSE)
00295             std::cout << "Added (immediate) " << lisnrID(lisnr)
00296                       << " to listeners list" << std::endl;
00297     }
00298 }
00299 
00300 
00301 #endif // EVENT_SENDER_CC_TEMPLATE
00302 

Generated on Sun Feb 16 16:56:21 2003 for C++ Event Handling Template Library by doxygen1.2.18