Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * interface_listener.cpp - BlackBoard event listener 00004 * 00005 * Created: Wed Nov 08 10:00:34 2007 00006 * Copyright 2007-2008 Tim Niemueller [www.niemueller.de] 00007 * 00008 ****************************************************************************/ 00009 00010 /* This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. A runtime exception applies to 00014 * this software (see LICENSE.GPL_WRE file mentioned below for details). 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU Library General Public License for more details. 00020 * 00021 * Read the full text in the LICENSE.GPL_WRE file in the doc directory. 00022 */ 00023 00024 #include <blackboard/interface_listener.h> 00025 #include <core/exceptions/system.h> 00026 #include <core/threading/mutex_locker.h> 00027 #include <interface/interface.h> 00028 #include <cstdlib> 00029 #include <cstring> 00030 #include <cstdio> 00031 00032 namespace fawkes { 00033 00034 /** @class BlackBoardInterfaceListener <blackboard/interface_listener.h> 00035 * BlackBoard interface listener. 00036 * Derive this class if you want to be notified of specific BlackBoard 00037 * events regarding instances of interfaces. 00038 * 00039 * The bb_interface_* methods are called during the appropriate operation. The 00040 * operation that you carry out in this event handler really has to damn fast, or 00041 * the performance of the whole system will suffer severely. For this reason use 00042 * this notification facility only rarely and only register for the appropriate 00043 * events. 00044 * 00045 * This class provides the basic infrastructure that can be used to build 00046 * your own event handler. During the life time of your event handler your 00047 * first add all the interfaces to the appropriate structures that you want 00048 * to listen for and add the interface types where you want to be notified 00049 * of creation events. 00050 * 00051 * The reader/writer added/removed and data changed notifications act upon a 00052 * specific interface. Any modification done with any instance of the interface 00053 * is reported to you. The interface creation notification deals only 00054 * with types of interfaces. There is no interface deletion notification because 00055 * the general idea is that you opened the interface by yourself for reading and 00056 * thus the deletion will not happen before you close the interface. 00057 * 00058 * You will not be notified if you change data of the interface that you registered 00059 * for or remove your own reading/writing instance of an interface. 00060 * 00061 * Here is a simple life cycle of a BlackBoard interface listener: 00062 * First you create your interface that you want to listen for. 00063 * The protected methods bbil_add_data_interface(), bbil_add_reader_interface(), 00064 * bbil_add_writer_interface() and bbil_add_interface_create_type() have to 00065 * be called with the appropriate interfaces <i>before</i> the event handler is 00066 * actually registered with the interface manager! From 00067 * now on will be called for the all registered events. 00068 * In the end you unregister the event listener and <i>then</i> close any 00069 * interface that you had registered before. 00070 * 00071 * It is important that you first unregister as an event handler before closing 00072 * the interface. Otherwise it could happen that you close the interface and 00073 * the instance is deleted and afterwards an event for that very interface 00074 * happens. A warning is reported via the LibLogger whenever you forget this. 00075 * 00076 * @author Tim Niemueller 00077 * @see BlackBoardInterfaceManager::register_listener() 00078 * @see BlackBoardInterfaceManager::unregister_listener() 00079 */ 00080 00081 /** Constructor. 00082 * @param name_format format of name to identify the listener, 00083 * see sprintf for supported tokens 00084 */ 00085 BlackBoardInterfaceListener::BlackBoardInterfaceListener(const char *name_format, ...) 00086 { 00087 va_list arg; 00088 va_start(arg, name_format); 00089 if (vasprintf(&__name, name_format, arg) == -1) { 00090 throw OutOfMemoryException("BlackBoardInterfaceListener ctor: vasprintf() failed"); 00091 } 00092 va_end(arg); 00093 } 00094 00095 00096 /** Destructor. */ 00097 BlackBoardInterfaceListener::~BlackBoardInterfaceListener() 00098 { 00099 while ( ! __bbil_data_interfaces.empty() ) { 00100 __bbil_ii = __bbil_data_interfaces.begin(); 00101 __bbil_data_interfaces.erase(__bbil_ii); 00102 } 00103 00104 while ( ! __bbil_reader_interfaces.empty() ) { 00105 __bbil_ii = __bbil_reader_interfaces.begin(); 00106 __bbil_reader_interfaces.erase(__bbil_ii); 00107 } 00108 00109 while ( ! __bbil_writer_interfaces.empty() ) { 00110 __bbil_ii = __bbil_writer_interfaces.begin(); 00111 __bbil_writer_interfaces.erase(__bbil_ii); 00112 } 00113 00114 free(__name); 00115 } 00116 00117 00118 /** Get BBIL name. 00119 * @return BBIL name 00120 */ 00121 const char * 00122 BlackBoardInterfaceListener::bbil_name() const 00123 { 00124 return __name; 00125 } 00126 00127 00128 /** BlackBoard data changed notification. 00129 * This is called whenever the data in an interface that you registered for is 00130 * modified. This happens if a writer calls the Interface::write() method. 00131 * @param interface interface instance that you supplied to bbil_add_data_interface() 00132 */ 00133 void 00134 BlackBoardInterfaceListener::bb_interface_data_changed(Interface *interface) throw() 00135 { 00136 } 00137 00138 00139 /** BlackBoard message received notification. 00140 * This is called whenever a message is received for this interface. This method is 00141 * only called for writing instances of an interface, never on reading instances. 00142 * If you have processed the message already, you can order that the message is not 00143 * enqueued by returning false. Returning true will enqueue the message as usual. 00144 * You should only do very (very!) quick tasks directly in this method, as it is 00145 * out of the regular thread context and can harm performance of other plugins and 00146 * the system as a whole. Note that if you decide to return false the message is 00147 * not referenced. If you want to keep it longer you have to ref() it by yourself. 00148 * An example where this would really make sense is a "STOP" message for the motor, 00149 * which needs to be processed ASAP and maybe even waiting a couple of miliseconds 00150 * for the next cycle is not acceptable. 00151 * @param interface interface instance that you supplied to bbil_add_message_interface() 00152 * @param message the message that was sent 00153 * @return true to get the message enqueued afterwards as usual, false to prevent 00154 * queuing of the message. 00155 */ 00156 bool 00157 BlackBoardInterfaceListener::bb_interface_message_received(Interface *interface, 00158 Message *message) throw() 00159 { 00160 return true; 00161 } 00162 00163 00164 /** A reading instance has been opened for a watched interface. 00165 * This is called whenever a reading instance of the interface you are watching 00166 * is opened. 00167 * @param interface interface instance that you supplied to bbil_add_reader_interface() 00168 * @param instance_serial the instance serial of the reading instance that has just been 00169 * added. 00170 */ 00171 void 00172 BlackBoardInterfaceListener::bb_interface_reader_added(Interface *interface, 00173 unsigned int instance_serial) throw() 00174 { 00175 } 00176 00177 00178 /** A reading instance has been closed for a watched interface. 00179 * This is called whenever a reading instance of an interface you are watching 00180 * is closed. 00181 * @param interface interface instance that you supplied to bbil_add_reader_interface() 00182 * @param instance_serial the instance serial of the reading instance that has just been 00183 * removed. 00184 */ 00185 void 00186 BlackBoardInterfaceListener::bb_interface_reader_removed(Interface *interface, 00187 unsigned int instance_serial) throw() 00188 { 00189 } 00190 00191 00192 /** A writing instance has been opened for a watched interface. 00193 * This is called whenever a writing instance of the interface you are watching 00194 * is opened. 00195 * @param interface interface instance that you supplied to bbil_add_writer_interface() 00196 * @param instance_serial the instance serial of the writing instance that has just been 00197 * added. 00198 */ 00199 void 00200 BlackBoardInterfaceListener::bb_interface_writer_added(Interface *interface, 00201 unsigned int instance_serial) throw() 00202 { 00203 } 00204 00205 00206 /** A writing instance has been closed for a watched interface. 00207 * This is called whenever a writing instance of an interface you are watching 00208 * is closed. 00209 * @param interface interface instance that you supplied to bbil_add_writer_interface() 00210 * @param instance_serial the instance serial of the writing instance that has just been 00211 * removed. 00212 */ 00213 void 00214 BlackBoardInterfaceListener::bb_interface_writer_removed(Interface *interface, 00215 unsigned int instance_serial) throw() 00216 { 00217 } 00218 00219 00220 /** Add an interface to the data modification watch list. 00221 * @param interface interface to watch for data modifications. 00222 */ 00223 void 00224 BlackBoardInterfaceListener::bbil_add_data_interface(Interface *interface) 00225 { 00226 MutexLocker lock(__bbil_data_interfaces.mutex()); 00227 if ( __bbil_data_interfaces.find((char *)interface->uid()) != __bbil_data_interfaces.end() ) { 00228 throw Exception("Interface %s already registered (data)", interface->uid()); 00229 } 00230 __bbil_data_interfaces[interface->uid()] = interface; 00231 } 00232 00233 /** Add an interface to the message received watch list. 00234 * @param interface interface to watch for messages 00235 */ 00236 void 00237 BlackBoardInterfaceListener::bbil_add_message_interface(Interface *interface) 00238 { 00239 MutexLocker lock(__bbil_message_interfaces.mutex()); 00240 if ( ! interface->is_writer() ) { 00241 throw Exception("Message received events can only be watched by writing instances"); 00242 } 00243 if ( __bbil_message_interfaces.find((char *)interface->uid()) != __bbil_message_interfaces.end() ) { 00244 throw Exception("Interface %s already registered (message)", interface->uid()); 00245 } 00246 __bbil_message_interfaces[interface->uid()] = interface; 00247 } 00248 00249 00250 /** Add an interface to the reader addition/removal watch list. 00251 * This method does not mean that you add interfaces that you opened for reading 00252 * but that you add an interface that you want to be informed for when reader 00253 * addition/removal happens. 00254 * @param interface interface to watch for addition/removal of readers 00255 */ 00256 void 00257 BlackBoardInterfaceListener::bbil_add_reader_interface(Interface *interface) 00258 { 00259 MutexLocker lock(__bbil_reader_interfaces.mutex()); 00260 if ( __bbil_reader_interfaces.find((char *)interface->uid()) != __bbil_reader_interfaces.end() ) { 00261 throw Exception("Interface %s already registered (reader)", interface->uid()); 00262 } 00263 __bbil_reader_interfaces[interface->uid()] = interface; 00264 } 00265 00266 00267 /** Add an interface to the writer addition/removal watch list. 00268 * This method does not mean that you add interfaces that you opened for writing 00269 * but that you add an interface that you want to be informed for when writer 00270 * addition/removal happens. 00271 * @param interface interface to watch for addition/removal of writers 00272 */ 00273 void 00274 BlackBoardInterfaceListener::bbil_add_writer_interface(Interface *interface) 00275 { 00276 MutexLocker lock(__bbil_writer_interfaces.mutex()); 00277 if ( __bbil_writer_interfaces.find((char *)interface->uid()) != __bbil_writer_interfaces.end() ) { 00278 throw Exception("Interface %s already registered (writer)", interface->uid()); 00279 } 00280 __bbil_writer_interfaces[interface->uid()] = interface; 00281 } 00282 00283 00284 00285 /** Remove an interface to the data modification watch list. 00286 * Only remove interfaces from the list when not currently registered to 00287 * the BlackBoard or chaos and confusion will come upon you. 00288 * @param interface interface to watch for data modifications. 00289 */ 00290 void 00291 BlackBoardInterfaceListener::bbil_remove_data_interface(Interface *interface) 00292 { 00293 MutexLocker lock(__bbil_data_interfaces.mutex()); 00294 if ( __bbil_data_interfaces.find((char *)interface->uid()) != __bbil_data_interfaces.end() ) { 00295 __bbil_data_interfaces.erase(interface->uid()); 00296 } 00297 } 00298 00299 /** Remove an interface to the message received watch list. 00300 * Only remove interfaces from the list when not currently registered to 00301 * the BlackBoard or chaos and confusion will come upon you. 00302 * @param interface interface to watch for messages 00303 */ 00304 void 00305 BlackBoardInterfaceListener::bbil_remove_message_interface(Interface *interface) 00306 { 00307 MutexLocker lock(__bbil_message_interfaces.mutex()); 00308 if ( ! interface->is_writer() ) { 00309 throw Exception("Message received events can only be watched by writing instances"); 00310 } 00311 if ( __bbil_message_interfaces.find((char *)interface->uid()) != __bbil_message_interfaces.end() ) { 00312 __bbil_message_interfaces.erase(interface->uid()); 00313 } 00314 } 00315 00316 00317 /** Remove an interface to the reader addition/removal watch list. 00318 * Only remove interfaces from the list when not currently registered to 00319 * the BlackBoard or chaos and confusion will come upon you. 00320 * @param interface interface to watch for addition/removal of readers 00321 */ 00322 void 00323 BlackBoardInterfaceListener::bbil_remove_reader_interface(Interface *interface) 00324 { 00325 MutexLocker lock(__bbil_reader_interfaces.mutex()); 00326 if ( __bbil_reader_interfaces.find((char *)interface->uid()) != __bbil_reader_interfaces.end() ) { 00327 __bbil_reader_interfaces.erase(interface->uid()); 00328 } 00329 } 00330 00331 00332 /** Remove an interface to the writer addition/removal watch list. 00333 * Only remove interfaces from the list when not currently registered to 00334 * the BlackBoard or chaos and confusion will come upon you. 00335 * @param interface interface to watch for addition/removal of writers 00336 */ 00337 void 00338 BlackBoardInterfaceListener::bbil_remove_writer_interface(Interface *interface) 00339 { 00340 MutexLocker lock(__bbil_writer_interfaces.mutex()); 00341 if ( __bbil_writer_interfaces.find((char *)interface->uid()) != __bbil_writer_interfaces.end() ) { 00342 __bbil_writer_interfaces.erase(interface->uid()); 00343 } 00344 } 00345 00346 00347 /** Get data modification watch list. 00348 * @return data modification watch list 00349 */ 00350 BlackBoardInterfaceListener::InterfaceLockMap * 00351 BlackBoardInterfaceListener::bbil_data_interfaces() throw() 00352 { 00353 return &__bbil_data_interfaces; 00354 } 00355 00356 /** Get message received watch list. 00357 * @return message received watch list 00358 */ 00359 BlackBoardInterfaceListener::InterfaceLockMap * 00360 BlackBoardInterfaceListener::bbil_message_interfaces() throw() 00361 { 00362 return &__bbil_message_interfaces; 00363 } 00364 00365 /** Get reader watch list. 00366 * @return reader watch list 00367 */ 00368 BlackBoardInterfaceListener::InterfaceLockMap * 00369 BlackBoardInterfaceListener::bbil_reader_interfaces() throw() 00370 { 00371 return &__bbil_reader_interfaces; 00372 } 00373 00374 /** Get writer watch list. 00375 * @return writer watch list 00376 */ 00377 BlackBoardInterfaceListener::InterfaceLockMap * 00378 BlackBoardInterfaceListener::bbil_writer_interfaces() throw() 00379 { 00380 return &__bbil_writer_interfaces; 00381 } 00382 00383 00384 /** Get interface instance for given UID. 00385 * A data modification notification is about to be triggered. For this the 00386 * interface instance that has been added to the event listener is determined. 00387 * @param iuid interface unique ID 00388 * @return interface instance, NULL if not in list (non-fatal error) 00389 */ 00390 Interface * 00391 BlackBoardInterfaceListener::bbil_data_interface(const char *iuid) throw() 00392 { 00393 MutexLocker lock(__bbil_data_interfaces.mutex()); 00394 if ((__bbil_ii = __bbil_data_interfaces.find((char *)iuid)) != __bbil_data_interfaces.end()) { 00395 return __bbil_ii->second; 00396 } else { 00397 return NULL; 00398 } 00399 } 00400 00401 00402 /** Get interface instance for given UID. 00403 * A message received notification is about to be triggered. For this the 00404 * interface instance that has been added to the event listener is determined. 00405 * @param iuid interface unique ID 00406 * @return interface instance, NULL if not in list (non-fatal error) 00407 */ 00408 Interface * 00409 BlackBoardInterfaceListener::bbil_message_interface(const char *iuid) throw() 00410 { 00411 MutexLocker lock(__bbil_data_interfaces.mutex()); 00412 if ((__bbil_ii = __bbil_message_interfaces.find((char *)iuid)) != __bbil_message_interfaces.end()) { 00413 return __bbil_ii->second; 00414 } else { 00415 return NULL; 00416 } 00417 } 00418 00419 00420 /** Get interface instance for given UID. 00421 * A reader notification is about to be triggered. For this the 00422 * interface instance that has been added to the event listener is determined. 00423 * @param iuid interface unique ID 00424 * @return interface instance, NULL if not in list (non-fatal error) 00425 */ 00426 Interface * 00427 BlackBoardInterfaceListener::bbil_reader_interface(const char *iuid) throw() 00428 { 00429 MutexLocker lock(__bbil_data_interfaces.mutex()); 00430 if ((__bbil_ii = __bbil_reader_interfaces.find((char *)iuid)) != __bbil_reader_interfaces.end()) { 00431 return __bbil_ii->second; 00432 } else { 00433 return NULL; 00434 } 00435 } 00436 00437 00438 /** Get interface instance for given UID. 00439 * A writer notification is about to be triggered. For this the 00440 * interface instance that has been added to the event listener is determined. 00441 * @param iuid interface unique ID 00442 * @return interface instance, NULL if not in list (non-fatal error) 00443 */ 00444 Interface * 00445 BlackBoardInterfaceListener::bbil_writer_interface(const char *iuid) throw() 00446 { 00447 MutexLocker lock(__bbil_data_interfaces.mutex()); 00448 if ((__bbil_ii = __bbil_writer_interfaces.find((char *)iuid)) != __bbil_writer_interfaces.end()) { 00449 return __bbil_ii->second; 00450 } else { 00451 return NULL; 00452 } 00453 } 00454 00455 } // end namespace fawkes