Fawkes API  Fawkes Development Version
blackboard.cpp
1 
2 /***************************************************************************
3  * blackboard.cpp - BlackBoard Interface
4  *
5  * Created: Sat Sep 16 17:11:13 2006 (on train to Cologne)
6  * Copyright 2006-2015 Tim Niemueller [www.niemueller.de]
7  ****************************************************************************/
8 
9 /* This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version. A runtime exception applies to
13  * this software (see LICENSE.GPL_WRE file mentioned below for details).
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Library General Public License for more details.
19  *
20  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
21  */
22 
23 #include <blackboard/blackboard.h>
24 #include <blackboard/internal/notifier.h>
25 
26 #include <string>
27 #include <cstring>
28 #include <cstdio>
29 #include <cstdlib>
30 
31 namespace fawkes {
32 #if 0 /* just to make Emacs auto-indent happy */
33 }
34 #endif
35 
36 /** @class BlackBoard <blackboard/blackboard.h>
37  * The BlackBoard abstract class.
38  * This class is the single one entry point for programs that use the BlackBoard.
39  * It is used to open and close interfaces, register and unregister listeners and
40  * observers and to maintain the BlackBoard shared memory segment. Not other classes
41  * shall be used directly.
42  *
43  * The BlackBoard holds a number of so-called interfaces. The interfaces store
44  * data and provide means to pass messages. The BlackBoard also allows for registering
45  * listeners and observers. The listeners can be used to get events for specific
46  * interfaces while the observer gets global interface creation and destruction
47  * events for a specified set of types of interfaces.
48 
49  * An interface consists of a few parts. First there is the storage block. This
50  * is a chunk of memory in the shared memory segment where the actual data is stored.
51  * Then there is the accessor object, an instance of a derivate of the Interface
52  * class which is used to access the data in the shared memory segment. Last but
53  * not least there is an internal message queue that can be used to pass messages
54  * from readers to the writer (not the other way around!).
55  *
56  * The interface manager keeps track of all the allocated interfaces. Events
57  * can be triggered if a specific interface changes (like logging the data to
58  * a file, sending it over the network or notifying another interface of such
59  * a change).
60  *
61  * Interfaces can only be instantiated through the BlackBoard. The BlackBoard
62  * instantiates an interface on request and guarantees that the instance
63  * is fully initialized and usable. This cannot be guaranteed if instantiating an
64  * interface through any other means!
65  *
66  * Interfaces can be opened for reading or writing, not both! There can be only
67  * one writer at a time for any given interface. Interfaces are identified via a
68  * type (which denotes the data and its semantics) and an identifier. There may
69  * be several interfaces for a given type, but the identifier has to be unique.
70  * The identifier is in most cases a well-known string that is used to share data
71  * among plugins.
72  *
73  * Interfaces provide a way to propagate data to the writer via messages. Available
74  * messages types depend on the interface type. Only matching messages are accepted
75  * and can be queued.
76  *
77  * The BlackBoard can operate in two modes, master and slave. Only the master
78  * creates and destroys the shared memory segment. Currently, the slave mode is not
79  * fully implemented and thus may not be used.
80  *
81  * @see Interface
82  * @see Message
83  *
84  * @author Tim Niemueller
85  *
86  *
87  * @fn Interface * BlackBoard::open_for_reading(const char *type, const char *identifier, const char *owner = NULL)
88  * Open interface for reading.
89  * This will create a new interface instance of the given type. The result can be
90  * casted to the appropriate type.
91  * @param type type of the interface
92  * @param identifier identifier of the interface
93  * @param owner name of entity which opened this interface. If using the BlackBoardAspect
94  * to access the blackboard leave this untouched unless you have a good reason.
95  * @return new fully initialized interface instance of requested type
96  * @exception OutOfMemoryException thrown if there is not enough free space for
97  * the requested interface.
98  *
99  *
100  * @fn Interface * BlackBoard::open_for_writing(const char *type, const char *identifier, const char *owner = NULL)
101  * Open interface for writing.
102  * This will create a new interface instance of the given type. The result can be
103  * casted to the appropriate type. This will only succeed if there is not already
104  * a writer for the given interface type/id!
105  * @param type type of the interface
106  * @param identifier identifier of the interface
107  * @param owner name of entity which opened this interface. If using the BlackBoardAspect
108  * to access the blackboard leave this untouched unless you have a good reason.
109  * @return new fully initialized interface instance of requested type
110  * @exception OutOfMemoryException thrown if there is not enough free space for
111  * the requested interface.
112  * @exception BlackBoardWriterActiveException thrown if there is already a writing
113  * instance with the same type/id
114  *
115  *
116  * @fn void BlackBoard::close(Interface *interface)
117  * Close interface.
118  * @param interface interface to close
119  *
120  *
121  * @fn bool BlackBoard::is_alive() const throw() = 0
122  * Check if the BlackBoard is still alive.
123  * @return true, if the BlackBoard is still alive and may be used, false otherwise.
124  *
125  * @fn bool BlackBoard::try_aliveness_restore() throw()
126  * Try to restore the aliveness of the BlackBoard instance.
127  * Note that even though the aliveness of the BlackBoard is restored single
128  * interfaces may still be invalid. That can for instance happen if a remote
129  * connection is re-established and a writer has been created during the
130  * downtime and an own writer instance of that very interface cannot be restored.
131  * @return true if the aliveness could be restored and the BlackBoard is
132  * operational again, false otherwise.
133  *
134  * @fn std::list<Interface *> BlackBoard::open_multiple_for_reading(const char *type_pattern, const char *id_pattern = "*", const char *owner = NULL)
135  * Open multiple interfaces for reading.
136  * This will create interface instances for currently registered interfaces of
137  * the given type that match the given ID pattern. The result can be casted to
138  * the appropriate type.
139  * @param type_pattern pattern of interface types to open, supports wildcards
140  * similar to filenames (*, ?, []), see "man fnmatch" for all supported.
141  * @param id_pattern pattern of interface IDs to open, supports wildcards similar
142  * to filenames (*, ?, []), see "man fnmatch" for all supported.
143  * @param owner name of entity which opened this interface. If using the BlackBoardAspect
144  * to access the blackboard leave this untouched unless you have a good reason.
145  * @return list of new fully initialized interface instances of requested type.
146  * You have to close all interfaces on your own when done with the list!
147  *
148  * @fn InterfaceInfoList * BlackBoard::list_all()
149  * Get list of all currently existing interfaces.
150  * @return list of interfaces
151  *
152  * @fn InterfaceInfoList * BlackBoard::list(const char *type_pattern, const char *id_pattern)
153  * Get list of interfaces matching type and ID patterns.
154  * See the fnmatch() documentation for possible patterns.
155  * @param type_pattern pattern with shell like globs (* for any number of
156  * characters, ? for exactly one character) to match the interface type.
157  * @param id_pattern pattern with shell like globs (* for any number of
158  * characters, ? for exactly one character) to match the interface ID.
159  * @return list of interfaces
160  *
161  */
162 
163 
164 /** Constructor.
165  * @param create_notifier true to create the notifier used for event
166  * notification, false not to create. Set to false only if you either
167  * forward notifier related calls or implement custom handling.
168  */
169 BlackBoard::BlackBoard(bool create_notifier)
170 {
171  if (create_notifier) {
173  } else {
174  __notifier = NULL;
175  }
176 }
177 
178 /** Destructor. */
180 {
181  delete __notifier;
182 }
183 
184 
185 /** Register BB event listener.
186  * @param listener BlackBoard event listener to register
187  * @param flag flags what to register for
188  */
189 void
192 {
193  if (! __notifier) throw NullPointerException("BlackBoard initialized without notifier");
194  __notifier->register_listener(listener, flag);
195 }
196 
197 
198 /** Update BB event listener.
199  * @param listener BlackBoard event listener to update
200  * @param flag flags what to update for
201  */
202 void
205 {
206  if (! __notifier) throw NullPointerException("BlackBoard initialized without notifier");
207  if (! listener) return;
208  __notifier->update_listener(listener, flag);
209 }
210 
211 
212 /** Unregister BB interface listener.
213  * This will remove the given BlackBoard interface listener from any
214  * event that it was previously registered for.
215  * @param listener BlackBoard event listener to remove
216  */
217 void
219 {
220  if (! __notifier) throw NullPointerException("BlackBoard initialized without notifier");
221  if (! listener) return;
222  __notifier->unregister_listener(listener);
223 }
224 
225 
226 /** Register BB interface observer.
227  * @param observer BlackBoard interface observer to register
228  */
229 void
231 {
232  if (! __notifier) throw NullPointerException("BlackBoard initialized without notifier");
233  if (! observer) return;
234  __notifier->register_observer(observer);
235 }
236 
237 
238 /** Unregister BB interface observer.
239  * This will remove the given BlackBoard event listener from any event that it was
240  * previously registered for.
241  * @param observer BlackBoard event listener to remove
242  */
243 void
245 {
246  if (! __notifier) throw NullPointerException("BlackBoard initialized without notifier");
247  if (! observer) return;
248  __notifier->unregister_observer(observer);
249 }
250 
251 
252 /** Produce interface name from C++ signature.
253  * This extracts the interface name for a mangled signature. It has
254  * has been coded with GCC (4) in mind and assumes interfaces to be
255  * in the fawkes namespace. It cannot deal with anythin else.
256  * @param type type name to strip
257  * @return stripped class type, use delete to free it after you are done
258  */
259 std::string
261 {
262  std::string t = type;
263  t = t.substr( 8 ); // Hack to remove N6fawkes namespace prefix
264  t = t.substr( t.find_first_not_of("0123456789") );
265  t = t.substr(0, t.length() - 1); // Hack to remove trailing letter
266  return t;
267 }
268 
269 
270 /** Get formatted identifier string.
271  * @param identifier_format identifier format string (sprintf syntax)
272  * @param arg arguments for format string
273  * @return formatted string
274  */
275 std::string
276 BlackBoard::format_identifier(const char *identifier_format, va_list arg)
277 {
278  char *id;
279  if (vasprintf(&id, identifier_format, arg) != -1 ) {
280  std::string id_s(id);
281  free(id);
282  return id_s;
283  } else {
284  throw Exception("Failed to generate identifier from format");
285  }
286 }
287 
288 /** Open interface for reading with identifier format string.
289  * This will create a new interface instance of the given type. The result can be
290  * casted to the appropriate type.
291  * @param interface_type type of the interface
292  * @param identifier identifier format string of the interface
293  * @param ... arguments for identifier format
294  * @return new fully initialized interface instance of requested type
295  * @exception OutOfMemoryException thrown if there is not enough free space for
296  * the requested interface.
297  */
298 Interface *
299 BlackBoard::open_for_reading_f(const char *interface_type,
300  const char *identifier, ...)
301 {
302  va_list arg;
303  va_start(arg, identifier);
304  Interface *iface = open_for_reading(interface_type,
305  format_identifier(identifier, arg).c_str());
306 
307  va_end(arg);
308  return iface;
309 }
310 
311 
312 /** Open interface for writing with identifier format string.
313  * This will create a new interface instance of the given type. The result can be
314  * casted to the appropriate type. This will only succeed if there is not already
315  * a writer for the given interface type/id!
316  * @param interface_type type of the interface
317  * @param identifier identifier format string of the interface
318  * @param ... arguments for identifier format
319  * @return new fully initialized interface instance of requested type
320  * @exception OutOfMemoryException thrown if there is not enough free space for
321  * the requested interface.
322  * @exception BlackBoardWriterActiveException thrown if there is already a writing
323  * instance with the same type/id
324  */
325 Interface *
326 BlackBoard::open_for_writing_f(const char *interface_type,
327  const char *identifier, ...)
328 {
329  va_list arg;
330  va_start(arg, identifier);
331  Interface *iface = open_for_writing(interface_type,
332  format_identifier(identifier, arg).c_str());
333 
334  va_end(arg);
335  return iface;
336 }
337 
338 
339 } // end namespace fawkes
virtual void register_observer(BlackBoardInterfaceObserver *observer)
Register BB interface observer.
Definition: blackboard.cpp:230
ListenerRegisterFlag
Flags to constrain listener registration/updates.
Definition: blackboard.h:98
std::string format_identifier(const char *identifier_format, va_list arg)
Get formatted identifier string.
Definition: blackboard.cpp:276
void update_listener(BlackBoardInterfaceListener *listener, BlackBoard::ListenerRegisterFlag flag)
Update BB event listener.
Definition: notifier.cpp:103
Fawkes library namespace.
virtual Interface * open_for_reading_f(const char *interface_type, const char *identifier,...)
Open interface for reading with identifier format string.
Definition: blackboard.cpp:299
void unregister_observer(BlackBoardInterfaceObserver *observer)
Unregister BB interface observer.
Definition: notifier.cpp:341
BlackBoard notifier.
Definition: notifier.h:43
A NULL pointer was supplied where not allowed.
Definition: software.h:34
virtual void unregister_listener(BlackBoardInterfaceListener *listener)
Unregister BB interface listener.
Definition: blackboard.cpp:218
virtual void update_listener(BlackBoardInterfaceListener *listener, ListenerRegisterFlag flag=BBIL_FLAG_ALL)
Update BB event listener.
Definition: blackboard.cpp:203
Base class for all Fawkes BlackBoard interfaces.
Definition: interface.h:79
virtual void register_listener(BlackBoardInterfaceListener *listener, ListenerRegisterFlag flag=BBIL_FLAG_ALL)
Register BB event listener.
Definition: blackboard.cpp:190
void unregister_listener(BlackBoardInterfaceListener *listener)
Unregister BB interface listener.
Definition: notifier.cpp:180
Base class for exceptions in Fawkes.
Definition: exception.h:36
virtual void unregister_observer(BlackBoardInterfaceObserver *observer)
Unregister BB interface observer.
Definition: blackboard.cpp:244
virtual Interface * open_for_writing_f(const char *interface_type, const char *identifier,...)
Open interface for writing with identifier format string.
Definition: blackboard.cpp:326
BlackBoardNotifier * __notifier
Notifier for BB events.
Definition: blackboard.h:122
BlackBoard interface observer.
BlackBoard(bool create_notifier=true)
Constructor.
Definition: blackboard.cpp:169
virtual ~BlackBoard()
Destructor.
Definition: blackboard.cpp:179
virtual Interface * open_for_reading(const char *interface_type, const char *identifier, const char *owner=NULL)=0
Open interface for reading.
void register_observer(BlackBoardInterfaceObserver *observer)
Register BB interface observer.
Definition: notifier.cpp:279
void register_listener(BlackBoardInterfaceListener *listener, BlackBoard::ListenerRegisterFlag flag)
Register BB event listener.
Definition: notifier.cpp:90
virtual Interface * open_for_writing(const char *interface_type, const char *identifier, const char *owner=NULL)=0
Open interface for writing.
BlackBoard interface listener.
std::string demangle_fawkes_interface_name(const char *type)
Produce interface name from C++ signature.
Definition: blackboard.cpp:260