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
00055
00056
00057
00058
00059
00060 if (_isBusySending)
00061 throw IllegalSendError();
00062
00063
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;
00075
00076
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
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
00118
00119 cleanupQueues();
00120 }
00121
00125 template<typename EvType>
00126 EventSender<EvType>::~EventSender()
00127 {
00128
00129 assert(!_isBusySending);
00130
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
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
00155 _registry.splice(_registry.end(), _registrationQueue, registryIter);
00156
00157 assert(std::find(_registrationQueue.begin(),
00158 _registrationQueue.end(), _registry.back())
00159 == _registrationQueue.end());
00160 }
00161
00162
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
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
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
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
00265 {
00266
00267 if (! removeFrom(_removalQueue, lisnr))
00268 {
00269
00270
00271
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
00280 {
00281 if (DEBUG_LEVEL >= DEBUG_VERBOSE)
00282 std::cout << lisnrID(lisnr)
00283 << " removed from registration queue"
00284 << std::endl;
00285 }
00286 }
00287 else
00288 {
00289
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