Initial import to Git
[profile/ivi/common-api-dbus-runtime.git] / src / CommonAPI / DBus / DBusMultiEvent.h
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 #ifndef COMMONAPI_DBUS_DBUS_MULTI_EVENT_H_
5 #define COMMONAPI_DBUS_DBUS_MULTI_EVENT_H_
6
7 #include <CommonAPI/Event.h>
8
9 #include <string>
10 #include <unordered_map>
11
12 namespace CommonAPI {
13 namespace DBus {
14
15 template <typename... _Arguments>
16 class DBusMultiEvent {
17  public:
18         typedef std::function<SubscriptionStatus(const std::string&, const _Arguments&...)> Listener;
19         typedef std::unordered_multimap<std::string, Listener> ListenersMap;
20         typedef typename ListenersMap::iterator Subscription;
21
22         Subscription subscribeAll(const Listener& listener);
23         Subscription subscribe(const std::string& name, const Listener& listener);
24
25         void unsubscribe(Subscription listenerSubscription);
26
27         virtual ~DBusMultiEvent() { }
28
29  protected:
30         SubscriptionStatus notifyListeners(const std::string& name, const _Arguments&... eventArguments);
31
32         virtual void onFirstListenerAdded(const std::string& name, const Listener& listener) { }
33         virtual void onListenerAdded(const std::string& name, const Listener& listener) { }
34
35         virtual void onListenerRemoved(const std::string& name, const Listener& listener) { }
36         virtual void onLastListenerRemoved(const std::string& name, const Listener& listener) { }
37
38  private:
39         typedef std::pair<typename ListenersMap::iterator, typename ListenersMap::iterator> IteratorRange;
40         SubscriptionStatus notifyListenersRange(const std::string& name, IteratorRange listenersRange, const _Arguments&... eventArguments);
41
42         ListenersMap listenersMap_;
43 };
44
45 template <typename... _Arguments>
46 typename DBusMultiEvent<_Arguments...>::Subscription
47 DBusMultiEvent<_Arguments...>::subscribeAll(const Listener& listener) {
48         return subscribe(std::string(), listener);
49 }
50
51 template <typename... _Arguments>
52 typename DBusMultiEvent<_Arguments...>::Subscription
53 DBusMultiEvent<_Arguments...>::subscribe(const std::string& name, const Listener& listener) {
54         const bool firstListenerAdded = listenersMap_.empty();
55
56         auto listenerSubscription = listenersMap_.insert({name, listener});
57
58         if (firstListenerAdded)
59                 onFirstListenerAdded(name, listener);
60
61         onListenerAdded(name, listener);
62
63         return listenerSubscription;
64 }
65
66 template <typename... _Arguments>
67 void DBusMultiEvent<_Arguments...>::unsubscribe(Subscription listenerSubscription) {
68         const std::string name = listenerSubscription->first;
69         const Listener listener = listenerSubscription->second;
70
71         listenersMap_.erase(listenerSubscription);
72
73         onListenerRemoved(name, listener);
74
75         const bool lastListenerRemoved = listenersMap_.empty();
76         if (lastListenerRemoved)
77                 onLastListenerRemoved(name, listener);
78 }
79
80 template <typename... _Arguments>
81 SubscriptionStatus DBusMultiEvent<_Arguments...>::notifyListeners(const std::string& name, const _Arguments&... eventArguments) {
82         const SubscriptionStatus subscriptionStatus = notifyListenersRange(name, listenersMap_.equal_range(name), eventArguments...);
83
84         if (subscriptionStatus == SubscriptionStatus::CANCEL)
85                 return SubscriptionStatus::CANCEL;
86
87         return notifyListenersRange(name, listenersMap_.equal_range(std::string()), eventArguments...);
88 }
89
90 template <typename... _Arguments>
91 SubscriptionStatus DBusMultiEvent<_Arguments...>::notifyListenersRange(
92                 const std::string& name,
93                 IteratorRange listenersRange,
94                 const _Arguments&... eventArguments) {
95         for (auto iterator = listenersRange.first; iterator != listenersRange.second; ) {
96                 const Listener& listener = iterator->second;
97                 const SubscriptionStatus listenerSubcriptionStatus = listener(name, eventArguments...);
98
99                 if (listenerSubcriptionStatus == SubscriptionStatus::CANCEL) {
100                         auto listenerIterator = iterator;
101                         listenersMap_.erase(listenerIterator);
102                         iterator++;
103                 } else
104                         iterator++;
105         }
106
107         return listenersMap_.empty() ? SubscriptionStatus::CANCEL : SubscriptionStatus::RETAIN;
108 }
109
110 } // namespace DBus
111 } // namespace CommonAPI
112
113 #endif // COMMONAPI_DBUS_DBUS_MULTI_EVENT_H_