source: XMLIO_V2/external/src/POCO/Foundation.save/Poco/AbstractEvent.h @ 80

Last change on this file since 80 was 80, checked in by ymipsl, 14 years ago

ajout lib externe

  • Property svn:eol-style set to native
File size: 11.1 KB
Line 
1//
2// AbstractEvent.h
3//
4// $Id: //poco/1.3/Foundation/include/Poco/AbstractEvent.h#2 $
5//
6// Library: Foundation
7// Package: Events
8// Module:  AbstractEvent
9//
10// Definition of the AbstractEvent class.
11//
12// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
13// and Contributors.
14//
15// Permission is hereby granted, free of charge, to any person or organization
16// obtaining a copy of the software and accompanying documentation covered by
17// this license (the "Software") to use, reproduce, display, distribute,
18// execute, and transmit the Software, and to prepare derivative works of the
19// Software, and to permit third-parties to whom the Software is furnished to
20// do so, all subject to the following:
21//
22// The copyright notices in the Software and this entire statement, including
23// the above license grant, this restriction and the following disclaimer,
24// must be included in all copies of the Software, in whole or in part, and
25// all derivative works of the Software, unless such copies or derivative
26// works are solely in the form of machine-executable object code generated by
27// a source language processor.
28//
29// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
32// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
33// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
34// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
35// DEALINGS IN THE SOFTWARE.
36//
37
38
39#ifndef  Foundation_AbstractFoundation_INCLUDED
40#define  Foundation_AbstractFoundation_INCLUDED
41
42
43#include "Poco/Foundation.h"
44#include "Poco/SingletonHolder.h"
45#include "Poco/SharedPtr.h"
46#include "Poco/ActiveResult.h"
47#include "Poco/ActiveMethod.h"
48#include "Poco/Mutex.h"
49
50
51namespace Poco {
52
53
54template <class TArgs, class TStrategy, class TDelegate> 
55class AbstractEvent
56        /// An AbstractEvent is the super-class of all events.
57        /// It works similar to the way C# handles notifications (aka events in C#).
58        /// Events can be used to send information to a set of observers
59        /// which are registered at the event. The type of the data is specified with
60        /// the template parameter TArgs. The TStrategy parameter must be a subclass
61        /// of NotificationStrategy. The parameter TDelegate can either be a subclass of AbstractDelegate
62        /// or of PriorityAbstractDelegate.
63        ///
64        /// Note that AbstractEvent should never be used directly. One ought to use
65        /// one of its subclasses which set the TStrategy and TDelegate template parameters
66        /// to fixed values. For most use-cases the BasicEvent template will be sufficient:
67        ///     #include "Poco/BasicEvent.h"
68        ///     #include "Poco/Delegate.h"
69        ///
70        /// If one requires delegates to be called in the order they registered, use FIFOEvent:
71        ///     #include "Poco/FIFOEvent.h"
72        ///     #include "Poco/Delegate.h"
73        ///
74        /// Both FIFOEvent and BasicEvent work with a standard delegate. They allow one object to register
75        /// exactly one delegate at an event. In contrast, a PriorityDelegate comes with an attached priority value
76        /// and allows one object to register for one priority value one delegate. Note that PriorityDelegates
77        /// only work with PriorityEvents:
78        ///     #include "Poco/PriorityEvent.h"
79        ///     #include "Poco/PriorityDelegate.h"
80        ///
81        /// Use events by adding them as public members to the object which is throwing notifications:
82        ///
83        ///     class MyData
84        ///     {
85        ///     public:
86        ///         Poco::BasicEvent<int> AgeChanged;
87        ///         
88        ///         MyData();
89        ///         ...
90        ///     };
91        ///
92        /// Throwing the event can be done either by the events notify() or notifyAsync() method:
93        ///
94        ///
95        /// Alternatively, instead of notify(), operator () can be used.
96        ///
97        ///     void MyData::setAge(int i)
98        ///     {
99        ///         this->_age = i;
100        ///         AgeChanged(this, this->_age);
101        ///     }
102        ///
103        /// Note that notify and notifyAsync do not catch exceptions, i.e. in case a delegate
104        /// throws an exception, the notify is immediately aborted and the exception is thrown
105        /// back to the caller.
106        ///
107        /// Delegates can register methods at the event. In the case of a BasicEvent or FIFOEvent
108        /// the Delegate template is used, in case of an PriorityEvent a PriorityDelegate is used.
109        /// Mixing of observers, e.g. using a PriorityDelegate with a BasicEvent is not possible and
110        /// checked for during compile time.
111        /// Events require the observers to follow one of the following method signature:
112        ///
113        ///     void onEvent(const void* pSender, TArgs& args);
114        ///     void onEvent(TArgs& args);
115        ///     static void onEvent(const void* pSender, TArgs& args);
116        ///     static void onEvent(void* pSender, TArgs& args);
117        ///     static void onEvent(TArgs& args);
118        ///
119        /// For performance reasons arguments are always sent by reference. This also allows observers
120        /// to modify the sent argument. To prevent that, use <const TArg> as template
121        /// parameter. A non-conformant method signature leads to compile errors.
122        ///
123        /// Assuming that the observer meets the method signature requirement, it can register
124        /// this method with the += operator:
125        ///
126        ///     class MyController
127        ///     {
128        ///     protected:
129        ///         MyData _data;
130        ///         
131        ///         void onDataChanged(void* pSender, int& data);
132        ///         ...
133        ///     };
134        ///         
135        ///     MyController::MyController()
136        ///     {
137        ///         _data.AgeChanged += delegate(this, &MyController::onDataChanged);
138        ///     }
139        ///
140        /// In some cases it might be desirable to work with automatically expiring registrations. Simply add
141        /// to delegate as 3rd parameter a expireValue (in milliseconds):
142        ///
143        ///     _data.DataChanged += delegate(this, &MyController::onDataChanged, 1000);
144        ///
145        /// This will add a delegate to the event which will automatically be removed in 1000 millisecs.
146        ///
147        /// Unregistering happens via the -= operator. Forgetting to unregister a method will lead to
148        /// segmentation faults later, when one tries to send a notify to a no longer existing object.
149        ///
150        ///     MyController::~MyController()
151        ///     {
152        ///         _data.DataChanged -= delegate(this, &MyController::onDataChanged);
153        ///     }
154        ///
155        /// Working with PriorityDelegates as similar to working with BasicEvent/FIFOEvent.Instead of ''delegate''
156        /// simply use ''priorityDelegate''.
157        ///
158        /// For further examples refer to the event testsuites.
159{
160public:
161        AbstractEvent(): 
162                _executeAsync(this, &AbstractEvent::executeAsyncImpl),
163                _enabled(true)
164        {
165        }
166
167        AbstractEvent(const TStrategy& strat): 
168                _executeAsync(this, &AbstractEvent::executeAsyncImpl),
169                _strategy(strat),
170                _enabled(true)
171        {       
172        }
173
174        virtual ~AbstractEvent()
175        {
176        }
177
178        void operator += (const TDelegate& aDelegate)
179                /// Adds a delegate to the event. If the observer is equal to an
180                /// already existing one (determined by the < operator),
181                /// it will simply replace the existing observer.
182                /// This behavior is determined by the TStrategy. Current implementations
183                /// (DefaultStrategy, FIFOStrategy) follow that guideline but future ones
184                /// can deviate.
185        {
186                FastMutex::ScopedLock lock(_mutex);
187                _strategy.add(aDelegate);
188        }
189       
190        void operator -= (const TDelegate& aDelegate)
191                /// Removes a delegate from the event. If the delegate is equal to an
192                /// already existing one is determined by the < operator.
193                /// If the observer is not found, the unregister will be ignored
194        {
195                FastMutex::ScopedLock lock(_mutex);
196                _strategy.remove(aDelegate);
197        }
198       
199        void operator () (const void* pSender, TArgs& args)
200        {
201                notify(pSender, args);
202        }
203
204        void notify(const void* pSender, TArgs& args)
205                /// Sends a notification to all registered delegates. The order is
206                /// determined by the TStrategy. This method is blocking. While executing,
207                /// other objects can change the list of delegates. These changes don't
208                /// influence the current active notifications but are activated with
209                /// the next notify. If one of the delegates throws an exception, the notify
210                /// method is immediately aborted and the exception is reported to the caller.
211        {
212                SharedPtr<TStrategy> ptrStrat;
213                bool enabled = false;
214               
215                {
216                        FastMutex::ScopedLock lock(_mutex);
217                        enabled = _enabled;
218                        if (_enabled)
219                        {
220                                // thread-safeness:
221                                // copy should be faster and safer than blocking until
222                                // execution ends
223                                ptrStrat = new TStrategy(_strategy);
224                        }
225                }
226
227                if (enabled)
228                {
229                        ptrStrat->notify(pSender, args);
230                }
231        }
232
233        ActiveResult<TArgs> notifyAsync(const void* pSender, const TArgs& args)
234                /// Sends a notification to all registered delegates. The order is
235                /// determined by the TStrategy. This method is not blocking and will
236                /// immediately return. The delegates are invoked in a seperate thread.
237                /// Call activeResult.wait() to wait until the notification has ended.
238                /// While executing, other objects can change the delegate list. These changes don't
239                /// influence the current active notifications but are activated with
240                /// the next notify. If one of the delegates throws an exception, the execution
241                /// is aborted and the exception is reported to the caller.
242        {
243                NotifyAsyncParams params(pSender, args);
244
245                {
246                        FastMutex::ScopedLock lock(_mutex);
247
248                        // thread-safeness:
249                        // copy should be faster and safer than blocking until
250                        // execution ends
251                        // make a copy of the strategy here to guarantee that
252                        // between notifyAsync and the execution of the method no changes can occur
253                               
254                        params.ptrStrat = SharedPtr<TStrategy>(new TStrategy(_strategy));
255                        params.enabled  = _enabled;
256                }
257
258                ActiveResult<TArgs> result = _executeAsync(params);
259                return result;
260        }
261       
262        void enable()
263                /// Enables the event
264        {
265                FastMutex::ScopedLock lock(_mutex);
266                _enabled = true;
267        }
268
269        void disable()
270                /// Disables the event. notify and notifyAsnyc will be ignored,
271                /// but adding/removing delegates is still allowed.
272        {
273                FastMutex::ScopedLock lock(_mutex);
274                _enabled = false;
275        }
276
277        bool isEnabled() const
278        {
279                FastMutex::ScopedLock lock(_mutex);
280                return _enabled;
281        }
282
283        void clear()
284                /// Removes all delegates.
285        {
286                FastMutex::ScopedLock lock(_mutex);
287                _strategy.clear();
288        }
289
290protected:
291        struct NotifyAsyncParams
292        {
293                SharedPtr<TStrategy> ptrStrat;
294                const void* pSender;
295                TArgs       args;
296                bool        enabled;
297               
298                NotifyAsyncParams(const void* pSend, const TArgs& a):ptrStrat(), pSender(pSend), args(a), enabled(true)
299                        /// default constructor reduces the need for TArgs to have an empty constructor, only copy constructor is needed.
300                {
301                }
302        };
303
304        ActiveMethod<TArgs, NotifyAsyncParams, AbstractEvent> _executeAsync;
305
306        TArgs executeAsyncImpl(const NotifyAsyncParams& par)
307        {
308                if (!par.enabled)
309                {
310                        return par.args;
311                }
312
313                NotifyAsyncParams params = par;
314                TArgs retArgs(params.args);
315                params.ptrStrat->notify(params.pSender, retArgs);
316                return retArgs;
317        }
318
319        TStrategy _strategy; /// The strategy used to notify observers.
320        bool      _enabled;  /// Stores if an event is enabled. Notfies on disabled events have no effect
321                             /// but it is possible to change the observers.
322        mutable FastMutex _mutex;
323
324private:
325        AbstractEvent(const AbstractEvent& other);
326        AbstractEvent& operator = (const AbstractEvent& other);
327};
328
329
330} // namespace Poco
331
332
333#endif
Note: See TracBrowser for help on using the repository browser.