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
31namespace 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 noexcept = 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() noexcept
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 */
165BlackBoard::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 */
184void
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 */
196void
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 */
211void
213{
214 if (!notifier_)
215 throw NullPointerException("BlackBoard initialized without notifier");
216 if (!listener)
217 return;
219}
220
221/** Register BB interface observer.
222 * @param observer BlackBoard interface observer to register
223 */
224void
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 */
239void
241{
242 if (!notifier_)
243 throw NullPointerException("BlackBoard initialized without notifier");
244 if (!observer)
245 return;
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 */
256std::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 */
271std::string
272BlackBoard::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 */
294Interface *
295BlackBoard::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 */
318Interface *
319BlackBoard::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:44
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:80
A NULL pointer was supplied where not allowed.
Definition: software.h:32
Fawkes library namespace.