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
34namespace 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
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 {
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.
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
void setAutoThrow(std::unique_ptr< std::exception > except)
If except is null, the mode will be set to Store if it was Except.
void respondeAll()
All currently stored callbacks will receive a response.
void throwAll(const std::exception &except)
All currently stored callbacks will receive the exception.
void addCallback(RespondFunction onRespond, ExceptFunction onExcept)
Adds an callback and processes it depending on the current mode.
void setAutoResponse(bool doAutoResponse=true)
setAutoResponse
std::function< void()> RespondFunction
void respondeN(std::size_t n)
The n oldest callbacks will receive a response.
std::function< void(const std::exception &)> ExceptFunction
void storeFurtherCallbacks()
All future callbacks will be stored.
This file offers overloads of toIce() and fromIce() functions for STL container types.