Fawkes API Fawkes Development Version
interface_list_maintainer.cpp
1
2/***************************************************************************
3 * interface_list_maintainer.cpp - BlackBoard interface list maintainer
4 *
5 * Created: Mon Mar 16 13:34:00 2015
6 * Copyright 2007-2014 Tim Niemueller [www.niemueller.de]
7 * 2015 Tobias Neumann
8 *
9 ****************************************************************************/
10
11/* This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version. A runtime exception applies to
15 * this software (see LICENSE.GPL_WRE file mentioned below for details).
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
23 */
24
25#include "interface_list_maintainer.h"
26
27#include <core/threading/mutex_locker.h>
28
29#include <algorithm>
30#include <string.h>
31
32using namespace fawkes;
33
34/** @class BlackBoardInterfaceListMaintainer "interface_list_maintainer.h"
35 * opens and maintains multiple interfaces defined by a pattern
36 * @author Tobias Neumann
37 */
38
39/** Constructor
40 * @param n name of plugin to use this
41 * @param bb pointer to the BlackBoard given by abstract
42 * @param l pointer to the Logger given by abstract
43 * @param type the interface type
44 * @param pattern the pattern for interfaces to open
45 *
46 */
47BlackBoardInterfaceListMaintainer::BlackBoardInterfaceListMaintainer(const char *n,
48 BlackBoard *bb,
49 Logger * l,
50 const char *type,
51 const char *pattern)
53{
54 blackboard_ = bb;
55 logger_ = l;
56 name_ = strdup(n);
57
58 bbio_add_observed_create(type, pattern);
59 blackboard_->register_observer(this);
60
61 MutexLocker lock(ifs_.mutex());
62
63 // for all interfaces of my pattern
64 std::list<fawkes::Interface *> ifs_tmp = blackboard_->open_multiple_for_reading(type, pattern);
65 std::list<fawkes::Interface *>::iterator pif_tmp;
66 for (pif_tmp = ifs_tmp.begin(); pif_tmp != ifs_tmp.end(); ++pif_tmp) {
67 // check if this is allready opened by me
68 std::string id_list_tmp((*pif_tmp)->id());
69 bool is_in_list = false;
71 for (pif_class = ifs_.begin(); pif_class != ifs_.end(); ++pif_class) {
72 std::string id_list_class((*pif_class)->id());
73
74 if (id_list_tmp.compare(id_list_class) == 0) {
75 blackboard_->close(*pif_tmp);
76 is_in_list = true;
77 }
78 }
79
80 if (!is_in_list) {
81 ifs_.push_back((*pif_tmp));
82 }
83
84 bbil_add_reader_interface((*pif_tmp));
85 bbil_add_writer_interface((*pif_tmp));
86 }
87 blackboard_->register_listener(this);
88
89 lock.unlock();
90}
91
92/** Destructor. */
94{
95 free(name_);
96
97 MutexLocker lock(ifs_.mutex());
99 for (pif = ifs_.begin(); pif != ifs_.end(); ++pif) {
102 blackboard_->update_listener(this);
103 blackboard_->close(*pif);
104 }
105}
106
107/**
108 * Callback if interface defined by the pattern is created.
109 * Now we try to open it.
110 * @param type the type of the created interface
111 * @param id the name of the interface
112 */
113void
114BlackBoardInterfaceListMaintainer::bb_interface_created(const char *type, const char *id) noexcept
115{
116 Interface *pif;
117 try {
118 pif = blackboard_->open_for_reading(type, id);
119 } catch (Exception &e) {
120 // ignored
121 logger_->log_warn(name_, "Failed to open %s:%s: %s", type, id, e.what_no_backtrace());
122 return;
123 }
124
125 try {
126 bbil_add_reader_interface(pif);
127 bbil_add_writer_interface(pif);
128 blackboard_->update_listener(this);
129 } catch (Exception &e) {
130 logger_->log_warn(name_, "Failed to register for %s:%s: %s", type, id, e.what());
131 try {
132 bbil_remove_reader_interface(pif);
133 bbil_remove_writer_interface(pif);
134 blackboard_->update_listener(this);
135 blackboard_->close(pif);
136 } catch (Exception &e) {
137 logger_->log_error(
138 name_, "Failed to deregister %s:%s during error recovery: %s", type, id, e.what());
139 }
140 return;
141 }
142
143 ifs_.push_back_locked(pif);
144}
145
146/**
147 * Callback if writer is removed from an interface. Now we check if we can close this interface.
148 * @param interface the interface that raised the callback
149 * @param instance_serial defiend by the callback, not used here
150 */
151void
152BlackBoardInterfaceListMaintainer::bb_interface_writer_removed(
153 fawkes::Interface *interface,
154 fawkes::Uuid instance_serial) noexcept
155{
156 conditional_close(interface);
157}
158
159/**
160 * Callback if a reader is removed from an interface. Now we check if we can close this interface.
161 * @param interface the interface that raised the callback
162 * @param instance_serial defiend by the callback, not used here
163 */
164void
165BlackBoardInterfaceListMaintainer::bb_interface_reader_removed(
166 fawkes::Interface *interface,
167 fawkes::Uuid instance_serial) noexcept
168{
169 conditional_close(interface);
170}
171
172/**
173 * Checks if the given interface can be closed and does so if possible.
174 * The check is, no writer and just one reader (us)
175 * @param pif interface to close
176 */
177void
178BlackBoardInterfaceListMaintainer::conditional_close(Interface *pif) noexcept
179{
180 bool close = false;
181 MutexLocker lock(ifs_.mutex());
182
183 LockList<Interface *>::iterator c = std::find(ifs_.begin(), ifs_.end(), pif);
184
185 if (c != ifs_.end() && (!pif->has_writer() && (pif->num_readers() == 1))) {
186 // It's only us
187 logger_->log_info(name_, "Last on %s, closing", pif->uid());
188 close = true;
189 ifs_.erase(c);
190 }
191
192 lock.unlock();
193
194 if (close) {
195 std::string uid = pif->uid();
196 try {
197 bbil_remove_reader_interface(pif);
198 bbil_remove_writer_interface(pif);
199 blackboard_->update_listener(this);
200 blackboard_->close(pif);
201 } catch (Exception &e) {
202 logger_->log_error(name_, "Failed to unregister or close %s: %s", uid.c_str(), e.what());
203 }
204 }
205}
206
207/** unlocks the mutex in this class
208 *
209 * this method needs to be called after lock_and_get_list()
210 * the list returned by lock_and_get_list() is invalid and shouldn't be used after this method is called
211 */
212void
214{
215 ifs_.unlock();
216}
void unlock_list()
unlocks the mutex in this class
BlackBoard interface listener.
void bbil_add_reader_interface(Interface *interface)
Add an interface to the reader addition/removal watch list.
void bbil_remove_reader_interface(Interface *interface)
Remove an interface to the reader addition/removal watch list.
void bbil_remove_writer_interface(Interface *interface)
Remove an interface to the writer addition/removal watch list.
void bbil_add_writer_interface(Interface *interface)
Add an interface to the writer addition/removal watch list.
void bbio_add_observed_create(const char *type_pattern, const char *id_pattern="*") noexcept
Add interface creation type to watch list.
The BlackBoard abstract class.
Definition: blackboard.h:46
virtual void update_listener(BlackBoardInterfaceListener *listener, ListenerRegisterFlag flag=BBIL_FLAG_ALL)
Update BB event listener.
Definition: blackboard.cpp:197
virtual void register_observer(BlackBoardInterfaceObserver *observer)
Register BB interface observer.
Definition: blackboard.cpp:225
virtual std::list< Interface * > open_multiple_for_reading(const char *type_pattern, const char *id_pattern="*", const char *owner=NULL)=0
Open multiple interfaces for reading.
virtual void register_listener(BlackBoardInterfaceListener *listener, ListenerRegisterFlag flag=BBIL_FLAG_ALL)
Register BB event listener.
Definition: blackboard.cpp:185
virtual void close(Interface *interface)=0
Close interface.
Base class for exceptions in Fawkes.
Definition: exception.h:36
virtual const char * what() const noexcept
Get primary string.
Definition: exception.cpp:639
virtual const char * what_no_backtrace() const noexcept
Get primary string (does not implicitly print the back trace).
Definition: exception.cpp:663
Base class for all Fawkes BlackBoard interfaces.
Definition: interface.h:80
const char * uid() const
Get unique identifier of interface.
Definition: interface.cpp:686
unsigned int num_readers() const
Get the number of readers.
Definition: interface.cpp:876
bool has_writer() const
Check if there is a writer for the interface.
Definition: interface.cpp:848
List with a lock.
Definition: lock_list.h:45
virtual void unlock() const
Unlock list.
Definition: lock_list.h:138
RefPtr< Mutex > mutex() const
Get access to the internal mutex.
Definition: lock_list.h:172
Interface for logging.
Definition: logger.h:42
Mutex locking helper.
Definition: mutex_locker.h:34
void unlock()
Unlock the mutex.
A convenience class for universally unique identifiers (UUIDs).
Definition: uuid.h:29
Fawkes library namespace.