Fawkes API  Fawkes Development Version
blackboard.cpp
00001 
00002 /***************************************************************************
00003  *  blackboard.cpp - BlackBoard Interface
00004  *
00005  *  Created: Sat Sep 16 17:11:13 2006 (on train to Cologne)
00006  *  Copyright  2006-2011  Tim Niemueller [www.niemueller.de]
00007  ****************************************************************************/
00008 
00009 /*  This program is free software; you can redistribute it and/or modify
00010  *  it under the terms of the GNU General Public License as published by
00011  *  the Free Software Foundation; either version 2 of the License, or
00012  *  (at your option) any later version. A runtime exception applies to
00013  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU Library General Public License for more details.
00019  *
00020  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00021  */
00022 
00023 #include <blackboard/blackboard.h>
00024 #include <blackboard/internal/notifier.h>
00025 
00026 #include <string>
00027 #include <cstring>
00028 
00029 namespace fawkes {
00030 #if 0 /* just to make Emacs auto-indent happy */
00031 }
00032 #endif
00033 
00034 /** @class BlackBoard <blackboard/blackboard.h>
00035  * The BlackBoard abstract class.
00036  * This class is the single one entry point for programs that use the BlackBoard.
00037  * It is used to open and close interfaces, register and unregister listeners and
00038  * observers and to maintain the BlackBoard shared memory segment. Not other classes
00039  * shall be used directly.
00040  *
00041  * The BlackBoard holds a number of so-called interfaces. The interfaces store
00042  * data and provide means to pass messages. The BlackBoard also allows for registering
00043  * listeners and observers. The listeners can be used to get events for specific
00044  * interfaces while the observer gets global interface creation and destruction
00045  * events for a specified set of types of interfaces.
00046 
00047  * An interface consists of a few parts. First there is the storage block. This
00048  * is a chunk of memory in the shared memory segment where the actual data is stored.
00049  * Then there is the accessor object, an instance of a derivate of the Interface
00050  * class which is used to access the data in the shared memory segment. Last but
00051  * not least there is an internal message queue that can be used to pass messages
00052  * from readers to the writer (not the other way around!).
00053  *
00054  * The interface manager keeps track of all the allocated interfaces. Events
00055  * can be triggered if a specific interface changes (like logging the data to
00056  * a file, sending it over the network or notifying another interface of such
00057  * a change).
00058  *
00059  * Interfaces can only be instantiated through the BlackBoard. The BlackBoard
00060  * instantiates an interface on request and guarantees that the instance
00061  * is fully initialized and usable. This cannot be guaranteed if instantiating an
00062  * interface through any other means!
00063  *
00064  * Interfaces can be opened for reading or writing, not both! There can be only
00065  * one writer at a time for any given interface. Interfaces are identified via a
00066  * type (which denotes the data and its semantics) and an identifier. There may
00067  * be several interfaces for a given type, but the identifier has to be unique.
00068  * The identifier is in most cases a well-known string that is used to share data
00069  * among plugins.
00070  *
00071  * Interfaces provide a way to propagate data to the writer via messages. Available
00072  * messages types depend on the interface type. Only matching messages are accepted
00073  * and can be queued.
00074  *
00075  * The BlackBoard can operate in two modes, master and slave. Only the master
00076  * creates and destroys the shared memory segment. Currently, the slave mode is not
00077  * fully implemented and thus may not be used.
00078  *
00079  * @see Interface
00080  * @see Message
00081  *
00082  * @author Tim Niemueller
00083  *
00084  *
00085  * @fn Interface *  BlackBoard::open_for_reading(const char *type, const char *identifier)
00086  * Open interface for reading.
00087  * This will create a new interface instance of the given type. The result can be
00088  * casted to the appropriate type.
00089  * @param type type of the interface
00090  * @param identifier identifier of the interface
00091  * @return new fully initialized interface instance of requested type
00092  * @exception OutOfMemoryException thrown if there is not enough free space for
00093  * the requested interface.
00094  *
00095  *
00096  * @fn Interface *  BlackBoard::open_for_writing(const char *type, const char *identifier)
00097  * Open interface for writing.
00098  * This will create a new interface instance of the given type. The result can be
00099  * casted to the appropriate type. This will only succeed if there is not already
00100  * a writer for the given interface type/id!
00101  * @param type type of the interface
00102  * @param identifier identifier of the interface
00103  * @return new fully initialized interface instance of requested type
00104  * @exception OutOfMemoryException thrown if there is not enough free space for
00105  * the requested interface.
00106  * @exception BlackBoardWriterActiveException thrown if there is already a writing
00107  * instance with the same type/id
00108  *
00109  *
00110  * @fn void BlackBoard::close(Interface *interface)
00111  * Close interface.
00112  * @param interface interface to close
00113  *
00114  *
00115  * @fn bool BlackBoard::is_alive() const throw() = 0
00116  * Check if the BlackBoard is still alive.
00117  * @return true, if the BlackBoard is still alive and may be used, false otherwise.
00118  *
00119  * @fn bool BlackBoard::try_aliveness_restore() throw()
00120  * Try to restore the aliveness of the BlackBoard instance.
00121  * Note that even though the aliveness of the BlackBoard is restored single
00122  * interfaces may still be invalid. That can for instance happen if a remote
00123  * connection is re-established and a writer has been created during the
00124  * downtime and an own writer instance of that very interface cannot be restored.
00125  * @return true if the aliveness could be restored and the BlackBoard is
00126  * operational again, false otherwise.
00127  *
00128  * @fn std::list<Interface *>  BlackBoard::open_multiple_for_reading(const char *type_pattern, const char *id_pattern = "*")
00129  * Open multiple interfaces for reading.
00130  * This will create interface instances for currently registered interfaces of
00131  * the given type that match the given ID pattern. The result can be casted to
00132  * the appropriate type.
00133  * @param type_pattern pattern of interface types to open, supports wildcards
00134  * similar to filenames (*, ?, []), see "man fnmatch" for all supported.
00135  * @param id_pattern pattern of interface IDs to open, supports wildcards similar
00136  * to filenames (*, ?, []), see "man fnmatch" for all supported.
00137  * @return list of new fully initialized interface instances of requested type.
00138  * You have to close all interfaces on your own when done with the list!
00139  *
00140  * @fn InterfaceInfoList * BlackBoard::list_all()
00141  * Get list of all currently existing interfaces.
00142  * @return list of interfaces
00143  *
00144  * @fn InterfaceInfoList * BlackBoard::list(const char *type_pattern, const char *id_pattern)
00145  * Get list of interfaces matching type and ID patterns.
00146  * See the fnmatch() documentation for possible patterns.
00147  * @param type_pattern pattern with shell like globs (* for any number of
00148  * characters, ? for exactly one character) to match the interface type.
00149  * @param id_pattern pattern with shell like globs (* for any number of
00150  * characters, ? for exactly one character) to match the interface ID.
00151  * @return list of interfaces
00152  *
00153  */
00154 
00155 
00156 /** Constructor. */
00157 BlackBoard::BlackBoard()
00158 {
00159   __notifier = new BlackBoardNotifier();
00160 }
00161 
00162 /** Destructor. */
00163 BlackBoard::~BlackBoard()
00164 {
00165   delete __notifier;
00166 }
00167 
00168 
00169 /** Register BB event listener.
00170  * @param listener BlackBoard event listener to register
00171  * @param flag flags what to register for
00172  */
00173 void
00174 BlackBoard::register_listener(BlackBoardInterfaceListener *listener,
00175                               ListenerRegisterFlag flag)
00176 {
00177   __notifier->register_listener(listener, flag);
00178 }
00179 
00180 
00181 /** Update BB event listener.
00182  * @param listener BlackBoard event listener to update
00183  * @param flag flags what to update for
00184  */
00185 void
00186 BlackBoard::update_listener(BlackBoardInterfaceListener *listener,
00187                             ListenerRegisterFlag flag)
00188 {
00189   if (! listener)  return;
00190   __notifier->update_listener(listener, flag);
00191 }
00192 
00193 
00194 /** Unregister BB interface listener.
00195  * This will remove the given BlackBoard interface listener from any
00196  * event that it was previously registered for.
00197  * @param listener BlackBoard event listener to remove
00198  */
00199 void
00200 BlackBoard::unregister_listener(BlackBoardInterfaceListener *listener)
00201 {
00202   if (! listener) return;
00203   __notifier->unregister_listener(listener);
00204 }
00205 
00206 
00207 /** Register BB interface observer.
00208  * @param observer BlackBoard interface observer to register
00209  */
00210 void
00211 BlackBoard::register_observer(BlackBoardInterfaceObserver *observer)
00212 {
00213   if (! observer) return;
00214   __notifier->register_observer(observer);
00215 }
00216 
00217 
00218 /** Unregister BB interface observer.
00219  * This will remove the given BlackBoard event listener from any event that it was
00220  * previously registered for.
00221  * @param observer BlackBoard event listener to remove
00222  */
00223 void
00224 BlackBoard::unregister_observer(BlackBoardInterfaceObserver *observer)
00225 {
00226   if (! observer) return;
00227   __notifier->unregister_observer(observer);
00228 }
00229 
00230 
00231 /** Produce interface name from C++ signature.
00232  * This extracts the interface name for a mangled signature. It has
00233  * has been coded with GCC (4) in mind and assumes interfaces to be
00234  * in the fawkes namespace. It cannot deal with anythin else.
00235  * @param type type name to strip
00236  * @return stripped class type, use delete to free it after you are done
00237  */
00238 std::string
00239 BlackBoard::demangle_fawkes_interface_name(const char *type)
00240 {
00241   std::string t = type;
00242   t = t.substr( 8 ); // Hack to remove N6fawkes namespace prefix
00243   t = t.substr( t.find_first_not_of("0123456789") );
00244   t = t.substr(0, t.length() - 1); // Hack to remove trailing letter
00245   return t;
00246 }
00247 
00248 
00249 } // end namespace fawkes