Fawkes API
Fawkes Development Version
|
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