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