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 
32 using 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  */
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  */
113 void
114 BlackBoardInterfaceListMaintainer::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  */
151 void
152 BlackBoardInterfaceListMaintainer::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  */
164 void
165 BlackBoardInterfaceListMaintainer::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  */
177 void
178 BlackBoardInterfaceListMaintainer::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  */
212 void
214 {
215  ifs_.unlock();
216 }
BlackBoardInterfaceListMaintainer(const char *n, BlackBoard *bb, Logger *l, const char *type, const char *pattern)
Constructor.
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.