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 <mutex>
28 #include <functional>
29 #include <stdexcept>
30 #include <memory>
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>
152  {
153  std::lock_guard<std::recursive_mutex> guard {classMutex};
154  switch (currentMode)
155  {
156  case Mode::Except:
157  onExcept(*exception);
158  return;
159  case Mode::Respond:
160  onRespond();
161  return;
162  case Mode::Store:
163  callbacks.emplace_back(CallbackHolder {std::move(onRespond), std::move(onExcept)});
164  return;
165  }
166  }
167 
168  template<class OnCloseExceptionT>
170  {
171  std::lock_guard<std::recursive_mutex> guard {classMutex};
172  if (doAutoResponse)
173  {
174  //set mode
175  currentMode = Mode::Respond;
176  exception = nullptr;
177  respondeAll();
178  return;
179  }
180  if (currentMode == Mode::Respond)
181  {
182  storeFurtherCallbacks();
183  }
184  }
185 
186  template<class OnCloseExceptionT>
188  {
189  std::lock_guard<std::recursive_mutex> guard {classMutex};
190  for (std::size_t i = 0; i < n && !callbacks.empty(); ++i)
191  {
192  callbacks.at(0).onRespond();
193  callbacks.pop_front();
194  }
195  }
196 
197  template<class OnCloseExceptionT>
199  {
200  std::lock_guard<std::recursive_mutex> guard {classMutex};
201  for (auto& cb : callbacks)
202  {
203  cb.onRespond();
204  }
205  callbacks.clear();
206  }
207 
208  template<class OnCloseExceptionT>
209  void AMDCallbackCollection<OnCloseExceptionT>::setAutoThrow(std::unique_ptr<std::exception> except)
210  {
211  std::lock_guard<std::recursive_mutex> guard {classMutex};
212  exception = except;
213  if (exception)
214  {
215  //set exception mode
216  currentMode = Mode::Except;
217  throwAll(*exception);
218  return;
219  }
220  if (currentMode == Mode::Except)
221  {
222  //reset exception mode.
223  storeFurtherCallbacks();
224  }
225  }
226 
227  template<class OnCloseExceptionT>
228  void AMDCallbackCollection<OnCloseExceptionT>::throwAll(const std::exception& except)
229  {
230  std::lock_guard<std::recursive_mutex> guard {classMutex};
231  for (auto& cb : callbacks)
232  {
233  cb.onExcept(except);
234  }
235  callbacks.clear();
236  }
237 
238  template<class OnCloseExceptionT>
240  {
241  std::lock_guard<std::recursive_mutex> guard {classMutex};
242  exception = nullptr;
243  currentMode = Mode::Store;
244  }
245 
246  template<class OnCloseExceptionT>
247  template<class IceCallbackT>
249  {
250  addCallback([cb] {cb->ice_response();}, [cb](const std::exception & e)
251  {
252  cb->ice_exception(e);
253  });
254  }
255 }
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:187
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:209
armarx::AMDCallbackCollection::addCallback
void addCallback(RespondFunction onRespond, ExceptFunction onExcept)
Adds an callback and processes it depending on the current mode.
Definition: AMDCallbackCollection.h:151
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:239
armarx::AMDCallbackCollection::respondeAll
void respondeAll()
All currently stored callbacks will receive a response.
Definition: AMDCallbackCollection.h:198
IceUtil::Handle
Definition: forward_declarations.h:29
armarx::AMDCallbackCollection::setAutoResponse
void setAutoResponse(bool doAutoResponse=true)
setAutoResponse
Definition: AMDCallbackCollection.h:169
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:228
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:28
armarx::AMDCallbackCollection::~AMDCallbackCollection
~AMDCallbackCollection()
Definition: AMDCallbackCollection.h:145