1//
2// ActiveResult.h
3//
4// Library: Foundation
5// Package: Threading
6// Module: ActiveObjects
7//
8// Definition of the ActiveResult class.
9//
10// Copyright (c) 2004-2007, Applied Informatics Software Engineering GmbH.
11// and Contributors.
12//
13// SPDX-License-Identifier: BSL-1.0
14//
15
16
17#ifndef Foundation_ActiveResult_INCLUDED
18#define Foundation_ActiveResult_INCLUDED
19
20
21#include "Poco/Foundation.h"
22#include "Poco/Mutex.h"
23#include "Poco/Event.h"
24#include "Poco/RefCountedObject.h"
25#include "Poco/Exception.h"
26#include <algorithm>
27
28
29namespace Poco {
30
31
32template <class ResultType>
33class ActiveResultHolder: public RefCountedObject
34 /// This class holds the result of an asynchronous method
35 /// invocation. It is used to pass the result from the
36 /// execution thread back to the invocation thread.
37 /// The class uses reference counting for memory management.
38 /// Do not use this class directly, use ActiveResult instead.
39{
40public:
41 ActiveResultHolder():
42 _pData(0),
43 _pExc(0),
44 _event(Event::EVENT_MANUALRESET)
45 /// Creates an ActiveResultHolder.
46 {
47 }
48
49 ResultType& data()
50 /// Returns a reference to the actual result.
51 {
52 poco_check_ptr(_pData);
53 return *_pData;
54 }
55
56 void data(ResultType* pData)
57 {
58 delete _pData;
59 _pData = pData;
60 }
61
62 void wait()
63 /// Pauses the caller until the result becomes available.
64 {
65 _event.wait();
66 }
67
68 bool tryWait(long milliseconds)
69 /// Waits up to the specified interval for the result to
70 /// become available. Returns true if the result became
71 /// available, false otherwise.
72 {
73 return _event.tryWait(milliseconds);
74 }
75
76 void wait(long milliseconds)
77 /// Waits up to the specified interval for the result to
78 /// become available. Throws a TimeoutException if the
79 /// result did not became available.
80 {
81 _event.wait(milliseconds);
82 }
83
84 void notify()
85 /// Notifies the invoking thread that the result became available.
86 {
87 _event.set();
88 }
89
90 bool failed() const
91 /// Returns true if the active method failed (and threw an exception).
92 /// Information about the exception can be obtained by calling error().
93 {
94 return _pExc != 0;
95 }
96
97 std::string error() const
98 /// If the active method threw an exception, a textual representation
99 /// of the exception is returned. An empty string is returned if the
100 /// active method completed successfully.
101 {
102 if (_pExc)
103 return _pExc->message();
104 else
105 return std::string();
106 }
107
108 Exception* exception() const
109 /// If the active method threw an exception, a clone of the exception
110 /// object is returned, otherwise null.
111 {
112 return _pExc;
113 }
114
115 void error(const Exception& exc)
116 /// Sets the exception.
117 {
118 delete _pExc;
119 _pExc = exc.clone();
120 }
121
122 void error(const std::string& msg)
123 /// Sets the exception.
124 {
125 delete _pExc;
126 _pExc = new UnhandledException(msg);
127 }
128
129protected:
130 ~ActiveResultHolder()
131 {
132 delete _pData;
133 delete _pExc;
134 }
135
136private:
137 ResultType* _pData;
138 Exception* _pExc;
139 Event _event;
140};
141
142
143
144template <>
145class ActiveResultHolder<void>: public RefCountedObject
146{
147public:
148 ActiveResultHolder():
149 _pExc(0),
150 _event(Event::EVENT_MANUALRESET)
151 /// Creates an ActiveResultHolder.
152 {
153 }
154
155 void wait()
156 /// Pauses the caller until the result becomes available.
157 {
158 _event.wait();
159 }
160
161 bool tryWait(long milliseconds)
162 /// Waits up to the specified interval for the result to
163 /// become available. Returns true if the result became
164 /// available, false otherwise.
165 {
166 return _event.tryWait(milliseconds);
167 }
168
169 void wait(long milliseconds)
170 /// Waits up to the specified interval for the result to
171 /// become available. Throws a TimeoutException if the
172 /// result did not became available.
173 {
174 _event.wait(milliseconds);
175 }
176
177 void notify()
178 /// Notifies the invoking thread that the result became available.
179 {
180 _event.set();
181 }
182
183 bool failed() const
184 /// Returns true if the active method failed (and threw an exception).
185 /// Information about the exception can be obtained by calling error().
186 {
187 return _pExc != 0;
188 }
189
190 std::string error() const
191 /// If the active method threw an exception, a textual representation
192 /// of the exception is returned. An empty string is returned if the
193 /// active method completed successfully.
194 {
195 if (_pExc)
196 return _pExc->message();
197 else
198 return std::string();
199 }
200
201 Exception* exception() const
202 /// If the active method threw an exception, a clone of the exception
203 /// object is returned, otherwise null.
204 {
205 return _pExc;
206 }
207
208 void error(const Exception& exc)
209 /// Sets the exception.
210 {
211 delete _pExc;
212 _pExc = exc.clone();
213 }
214
215 void error(const std::string& msg)
216 /// Sets the exception.
217 {
218 delete _pExc;
219 _pExc = new UnhandledException(msg);
220 }
221
222protected:
223 ~ActiveResultHolder()
224 {
225 delete _pExc;
226 }
227
228private:
229 Exception* _pExc;
230 Event _event;
231};
232
233
234template <class RT>
235class ActiveResult
236 /// This class holds the result of an asynchronous method
237 /// invocation (see class ActiveMethod). It is used to pass the
238 /// result from the execution thread back to the invocation thread.
239{
240public:
241 typedef RT ResultType;
242 typedef ActiveResultHolder<ResultType> ActiveResultHolderType;
243
244 ActiveResult(ActiveResultHolderType* pHolder):
245 _pHolder(pHolder)
246 /// Creates the active result. For internal use only.
247 {
248 poco_check_ptr (pHolder);
249 }
250
251 ActiveResult(const ActiveResult& result)
252 /// Copy constructor.
253 {
254 _pHolder = result._pHolder;
255 _pHolder->duplicate();
256 }
257
258 ~ActiveResult()
259 /// Destroys the result.
260 {
261 _pHolder->release();
262 }
263
264 ActiveResult& operator = (const ActiveResult& result)
265 /// Assignment operator.
266 {
267 ActiveResult tmp(result);
268 swap(tmp);
269 return *this;
270 }
271
272 void swap(ActiveResult& result)
273 {
274 using std::swap;
275 swap(_pHolder, result._pHolder);
276 }
277
278 ResultType& data() const
279 /// Returns a reference to the result data.
280 {
281 return _pHolder->data();
282 }
283
284 void data(ResultType* pValue)
285 {
286 _pHolder->data(pValue);
287 }
288
289 void wait()
290 /// Pauses the caller until the result becomes available.
291 {
292 _pHolder->wait();
293 }
294
295 bool tryWait(long milliseconds)
296 /// Waits up to the specified interval for the result to
297 /// become available. Returns true if the result became
298 /// available, false otherwise.
299 {
300 return _pHolder->tryWait(milliseconds);
301 }
302
303 void wait(long milliseconds)
304 /// Waits up to the specified interval for the result to
305 /// become available. Throws a TimeoutException if the
306 /// result did not became available.
307 {
308 _pHolder->wait(milliseconds);
309 }
310
311 bool available() const
312 /// Returns true if a result is available.
313 {
314 return _pHolder->tryWait(0);
315 }
316
317 bool failed() const
318 /// Returns true if the active method failed (and threw an exception).
319 /// Information about the exception can be obtained by calling error().
320 {
321 return _pHolder->failed();
322 }
323
324 std::string error() const
325 /// If the active method threw an exception, a textual representation
326 /// of the exception is returned. An empty string is returned if the
327 /// active method completed successfully.
328 {
329 return _pHolder->error();
330 }
331
332 Exception* exception() const
333 /// If the active method threw an exception, a clone of the exception
334 /// object is returned, otherwise null.
335 {
336 return _pHolder->exception();
337 }
338
339 void notify()
340 /// Notifies the invoking thread that the result became available.
341 /// For internal use only.
342 {
343 _pHolder->notify();
344 }
345
346 ResultType& data()
347 /// Returns a non-const reference to the result data. For internal
348 /// use only.
349 {
350 return _pHolder->data();
351 }
352
353 void error(const std::string& msg)
354 /// Sets the failed flag and the exception message.
355 {
356 _pHolder->error(msg);
357 }
358
359 void error(const Exception& exc)
360 /// Sets the failed flag and the exception message.
361 {
362 _pHolder->error(exc);
363 }
364
365private:
366 ActiveResult();
367
368 ActiveResultHolderType* _pHolder;
369};
370
371
372
373template <>
374class ActiveResult<void>
375 /// This class holds the result of an asynchronous method
376 /// invocation (see class ActiveMethod). It is used to pass the
377 /// result from the execution thread back to the invocation thread.
378{
379public:
380 typedef ActiveResultHolder<void> ActiveResultHolderType;
381
382 ActiveResult(ActiveResultHolderType* pHolder):
383 _pHolder(pHolder)
384 /// Creates the active result. For internal use only.
385 {
386 poco_check_ptr (pHolder);
387 }
388
389 ActiveResult(const ActiveResult& result)
390 /// Copy constructor.
391 {
392 _pHolder = result._pHolder;
393 _pHolder->duplicate();
394 }
395
396 ~ActiveResult()
397 /// Destroys the result.
398 {
399 _pHolder->release();
400 }
401
402 ActiveResult& operator = (const ActiveResult& result)
403 /// Assignment operator.
404 {
405 ActiveResult tmp(result);
406 swap(tmp);
407 return *this;
408 }
409
410 void swap(ActiveResult& result)
411 {
412 using std::swap;
413 swap(_pHolder, result._pHolder);
414 }
415
416 void wait()
417 /// Pauses the caller until the result becomes available.
418 {
419 _pHolder->wait();
420 }
421
422 bool tryWait(long milliseconds)
423 /// Waits up to the specified interval for the result to
424 /// become available. Returns true if the result became
425 /// available, false otherwise.
426 {
427 return _pHolder->tryWait(milliseconds);
428 }
429
430 void wait(long milliseconds)
431 /// Waits up to the specified interval for the result to
432 /// become available. Throws a TimeoutException if the
433 /// result did not became available.
434 {
435 _pHolder->wait(milliseconds);
436 }
437
438 bool available() const
439 /// Returns true if a result is available.
440 {
441 return _pHolder->tryWait(0);
442 }
443
444 bool failed() const
445 /// Returns true if the active method failed (and threw an exception).
446 /// Information about the exception can be obtained by calling error().
447 {
448 return _pHolder->failed();
449 }
450
451 std::string error() const
452 /// If the active method threw an exception, a textual representation
453 /// of the exception is returned. An empty string is returned if the
454 /// active method completed successfully.
455 {
456 return _pHolder->error();
457 }
458
459 Exception* exception() const
460 /// If the active method threw an exception, a clone of the exception
461 /// object is returned, otherwise null.
462 {
463 return _pHolder->exception();
464 }
465
466 void notify()
467 /// Notifies the invoking thread that the result became available.
468 /// For internal use only.
469 {
470 _pHolder->notify();
471 }
472
473 void error(const std::string& msg)
474 /// Sets the failed flag and the exception message.
475 {
476 _pHolder->error(msg);
477 }
478
479 void error(const Exception& exc)
480 /// Sets the failed flag and the exception message.
481 {
482 _pHolder->error(exc);
483 }
484
485private:
486 ActiveResult();
487
488 ActiveResultHolderType* _pHolder;
489};
490
491
492} // namespace Poco
493
494
495#endif // Foundation_ActiveResult_INCLUDED
496