AMDCallbackCollection.h
Go to the documentation of this file.
1 /*
2  * This file is part of ArmarX.
3  *
4  * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5  *
6  * ArmarX is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * ArmarX is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18 * @package ArmarXCore
19 * @author Raphael Grimm ( raphael dot grimm at kit dot edu)
20 * @date 2016
21 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22 * GNU General Public License
23 */
24 #pragma once
25 
26 #include <deque>
27 #include <functional>
28 #include <memory>
29 #include <mutex>
30 #include <stdexcept>
31 
32 #include <ArmarXCore/interface/core/UserException.h>
33 
34 namespace armarx
35 {
36  /**
37  * @brief This helper-class can be used when you have an ice AMD method.
38  * It holds the ice function callbacks or custom fuctions to respond or pass an exception..
39  * Furthermore an excpetion will be passed if this class destroys and some clients are still waiting.
40  *
41  * A usecase for this class would be the following scenario:
42  * A server S does a long calculation and some clients wait for the result.
43  * The server may want to offer a wait function to the clients.
44  * Since the server does not want to block threads for waiting the function should be tagged ["amd"] in the slice definition.
45  * If a client calls the function, S receives a function callback to send a response or an exception.
46  * The server now can use an AMDCallbackCollection to store all callbacks and send an
47  * exception or responde to all or some of the stored callbacks.
48  * @see https://doc.zeroc.com/pages/viewpage.action?pageId=14031073
49  * \ingroup Distributed
50  */
51  template <class OnCloseExceptionT = ServerShuttingDown>
53  {
54  public:
55  using ExceptFunction = std::function<void(const std::exception&)>;
56  using RespondFunction = std::function<void()>;
57 
58  AMDCallbackCollection() = default;
59  inline ~AMDCallbackCollection();
60  /**
61  * @brief Adds an callback and processes it depending on the current mode.
62  * @param onRespond The function called to responde.
63  * @param onExcept The function called on exception.
64  */
65  inline void addCallback(RespondFunction onRespond, ExceptFunction onExcept);
66 
67  /**
68  * @brief Adds an callback and processes it depending on the current mode.
69  * The callback is created using the ice_response and ice_exception functions of the callback object.
70  * @param cb The function callback from ice.
71  */
72  template <class IceCallbackT>
74 
75  /**
76  * @brief setAutoResponse
77  * @param doAutoResponse If set the mode will change to \ref Respond.
78  * If false the mode will change from \ref Respond to \ref Store
79  */
80  inline void setAutoResponse(bool doAutoResponse = true);
81 
82  /**
83  * @brief The n oldest callbacks will receive a response.
84  * @param n
85  *
86  * This may be used in an producer/consumer scenario where the producer creates multiple objects.
87  */
88  inline void respondeN(std::size_t n);
89 
90  /**
91  * @brief All currently stored callbacks will receive a response.
92  */
93  inline void respondeAll();
94 
95  /**
96  * @brief If except is null, the mode will be set to \ref Store if it was \ref Except.
97  * If except is not null, all currently stored and future callbacks will receive the exception.
98  * @param except
99  */
100  inline void setAutoThrow(std::unique_ptr<std::exception> except);
101 
102  /**
103  * @brief All currently stored callbacks will receive the exception.
104  * @param except The exception.
105  */
106  inline void throwAll(const std::exception& except);
107 
108  /**
109  * @brief All future callbacks will be stored.
110  */
111  inline void storeFurtherCallbacks();
112 
113  private:
114  struct CallbackHolder
115  {
116  RespondFunction onRespond;
117  ExceptFunction onExcept;
118  };
119  /**
120  * @brief The mode of the class AMDCallbackCollection.
121  */
122  enum class Mode
123  {
124  /**
125  * @brief All callbacks will be stored.
126  */
127  Store,
128  /**
129  * @brief All callbacks will get a response.
130  */
131  Respond,
132  /**
133  * @brief All callbacks will get an exception.
134  */
135  Except
136  };
137 
138  std::deque<CallbackHolder> callbacks;
139  Mode currentMode{Mode::Store};
140  std::unique_ptr<std::exception> exception;
141  std::recursive_mutex classMutex;
142  };
143 
144  template <class OnCloseExceptionT>
146  {
147  throwAll(OnCloseExceptionT{"AMDCallbackCollection dtor."});
148  }
149 
150  template <class OnCloseExceptionT>
151  void
155  {
156  std::lock_guard<std::recursive_mutex> guard{classMutex};
157  switch (currentMode)
158  {
159  case Mode::Except:
160  onExcept(*exception);
161  return;
162  case Mode::Respond:
163  onRespond();
164  return;
165  case Mode::Store:
166  callbacks.emplace_back(CallbackHolder{std::move(onRespond), std::move(onExcept)});
167  return;
168  }
169  }
170 
171  template <class OnCloseExceptionT>
172  void
174  {
175  std::lock_guard<std::recursive_mutex> guard{classMutex};
176  if (doAutoResponse)
177  {
178  //set mode
179  currentMode = Mode::Respond;
180  exception = nullptr;
181  respondeAll();
182  return;
183  }
184  if (currentMode == Mode::Respond)
185  {
186  storeFurtherCallbacks();
187  }
188  }
189 
190  template <class OnCloseExceptionT>
191  void
193  {
194  std::lock_guard<std::recursive_mutex> guard{classMutex};
195  for (std::size_t i = 0; i < n && !callbacks.empty(); ++i)
196  {
197  callbacks.at(0).onRespond();
198  callbacks.pop_front();
199  }
200  }
201 
202  template <class OnCloseExceptionT>
203  void
205  {
206  std::lock_guard<std::recursive_mutex> guard{classMutex};
207  for (auto& cb : callbacks)
208  {
209  cb.onRespond();
210  }
211  callbacks.clear();
212  }
213 
214  template <class OnCloseExceptionT>
215  void
216  AMDCallbackCollection<OnCloseExceptionT>::setAutoThrow(std::unique_ptr<std::exception> except)
217  {
218  std::lock_guard<std::recursive_mutex> guard{classMutex};
219  exception = except;
220  if (exception)
221  {
222  //set exception mode
223  currentMode = Mode::Except;
224  throwAll(*exception);
225  return;
226  }
227  if (currentMode == Mode::Except)
228  {
229  //reset exception mode.
230  storeFurtherCallbacks();
231  }
232  }
233 
234  template <class OnCloseExceptionT>
235  void
237  {
238  std::lock_guard<std::recursive_mutex> guard{classMutex};
239  for (auto& cb : callbacks)
240  {
241  cb.onExcept(except);
242  }
243  callbacks.clear();
244  }
245 
246  template <class OnCloseExceptionT>
247  void
249  {
250  std::lock_guard<std::recursive_mutex> guard{classMutex};
251  exception = nullptr;
252  currentMode = Mode::Store;
253  }
254 
255  template <class OnCloseExceptionT>
256  template <class IceCallbackT>
257  void
259  {
260  addCallback([cb] { cb->ice_response(); },
261  [cb](const std::exception& e) { cb->ice_exception(e); });
262  }
263 } // namespace armarx
armarx::AMDCallbackCollection::AMDCallbackCollection
AMDCallbackCollection()=default
armarx::AMDCallbackCollection::respondeN
void respondeN(std::size_t n)
The n oldest callbacks will receive a response.
Definition: AMDCallbackCollection.h:192
armarx::AMDCallbackCollection::setAutoThrow
void setAutoThrow(std::unique_ptr< std::exception > except)
If except is null, the mode will be set to Store if it was Except.
Definition: AMDCallbackCollection.h:216
magic_enum::detail::n
constexpr auto n() noexcept
Definition: magic_enum.hpp:418
armarx::AMDCallbackCollection::addCallback
void addCallback(RespondFunction onRespond, ExceptFunction onExcept)
Adds an callback and processes it depending on the current mode.
Definition: AMDCallbackCollection.h:152
armarx::AMDCallbackCollection::ExceptFunction
std::function< void(const std::exception &)> ExceptFunction
Definition: AMDCallbackCollection.h:55
armarx::AMDCallbackCollection::storeFurtherCallbacks
void storeFurtherCallbacks()
All future callbacks will be stored.
Definition: AMDCallbackCollection.h:248
armarx::AMDCallbackCollection::respondeAll
void respondeAll()
All currently stored callbacks will receive a response.
Definition: AMDCallbackCollection.h:204
IceUtil::Handle
Definition: forward_declarations.h:30
armarx::AMDCallbackCollection::setAutoResponse
void setAutoResponse(bool doAutoResponse=true)
setAutoResponse
Definition: AMDCallbackCollection.h:173
armarx::AMDCallbackCollection::RespondFunction
std::function< void()> RespondFunction
Definition: AMDCallbackCollection.h:56
armarx::AMDCallbackCollection
This helper-class can be used when you have an ice AMD method.
Definition: AMDCallbackCollection.h:52
armarx::AMDCallbackCollection::throwAll
void throwAll(const std::exception &except)
All currently stored callbacks will receive the exception.
Definition: AMDCallbackCollection.h:236
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27
armarx::AMDCallbackCollection::~AMDCallbackCollection
~AMDCallbackCollection()
Definition: AMDCallbackCollection.h:145