interface_listener.cpp

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

Generated on Tue Feb 22 13:32:25 2011 for Fawkes API by  doxygen 1.4.7