From 0e0aee2aa57114693ba051b2524dcc400966e266 Mon Sep 17 00:00:00 2001 From: Stefan Laner Date: Mon, 29 Jul 2013 16:36:07 +0200 Subject: Added support for selective broadcasts -Add subclass for event to support additional API for selective -Add hash specialisation for ClientID hashes Change-Id: Ic708338c5e4a821c908a174ca373d212b5f7b3ee --- Makefile.am | 5 +- src/CommonAPI/ContainerUtils.cpp | 21 +++++ src/CommonAPI/ContainerUtils.h | 33 +++++++ src/CommonAPI/Event.h | 197 ++++++++++++++++++++------------------- src/CommonAPI/SelectiveEvent.h | 38 ++++++++ src/CommonAPI/Stub.h | 30 +++--- src/CommonAPI/types.h | 21 +++++ 7 files changed, 237 insertions(+), 108 deletions(-) create mode 100644 src/CommonAPI/ContainerUtils.cpp create mode 100644 src/CommonAPI/ContainerUtils.h create mode 100644 src/CommonAPI/SelectiveEvent.h diff --git a/Makefile.am b/Makefile.am index 136aac9..e1fc9ab 100644 --- a/Makefile.am +++ b/Makefile.am @@ -35,7 +35,8 @@ lib_LTLIBRARIES = libCommonAPI.la libCommonAPI_la_SOURCES = \ src/CommonAPI/Runtime.cpp \ - src/CommonAPI/Configuration.cpp + src/CommonAPI/Configuration.cpp \ + src/CommonAPI/ContainerUtils.cpp CommonAPI_includedir=$(includedir)/CommonAPI-${VERSION}/CommonAPI CommonAPI_include_HEADERS = \ @@ -44,6 +45,7 @@ CommonAPI_include_HEADERS = \ src/CommonAPI/ByteBuffer.h \ src/CommonAPI/CommonAPI.h \ src/CommonAPI/Configuration.h \ + src/CommonAPI/ContainerUtils.h \ src/CommonAPI/Event.h \ src/CommonAPI/Factory.h \ src/CommonAPI/Factory.hpp \ @@ -53,6 +55,7 @@ CommonAPI_include_HEADERS = \ src/CommonAPI/OutputStream.h \ src/CommonAPI/Proxy.h \ src/CommonAPI/Runtime.h \ + src/CommonAPI/SelectiveEvent.h \ src/CommonAPI/SerializableStruct.h \ src/CommonAPI/SerializableVariant.h \ src/CommonAPI/SerializableVariant.hpp \ diff --git a/src/CommonAPI/ContainerUtils.cpp b/src/CommonAPI/ContainerUtils.cpp new file mode 100644 index 0000000..bb1a360 --- /dev/null +++ b/src/CommonAPI/ContainerUtils.cpp @@ -0,0 +1,21 @@ +/* Copyright (C) 2013 BMW Group + * Author: Manfred Bathelt (manfred.bathelt@bmw.de) + * Author: Juergen Gehring (juergen.gehring@bmw.de) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ContainerUtils.h" +#include "types.h" + +namespace CommonAPI { + +size_t SharedPointerClientIdContentHash::operator()(const std::shared_ptr& t) const { + return t->hashCode(); +} + +bool SharedPointerClientIdContentEqual::operator()(const std::shared_ptr& a, const std::shared_ptr& b) const { + return *a==*b; +} + +} // namespace std diff --git a/src/CommonAPI/ContainerUtils.h b/src/CommonAPI/ContainerUtils.h new file mode 100644 index 0000000..a4423ab --- /dev/null +++ b/src/CommonAPI/ContainerUtils.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2013 BMW Group + * Author: Manfred Bathelt (manfred.bathelt@bmw.de) + * Author: Juergen Gehring (juergen.gehring@bmw.de) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#if !defined (COMMONAPI_INTERNAL_COMPILATION) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#ifndef FUNCTIONALHASH_H_ +#define FUNCTIONALHASH_H_ + +#include +#include + +namespace CommonAPI { +class ClientId; + +struct SharedPointerClientIdContentHash : public std::unary_function, size_t> { + size_t operator()(const std::shared_ptr& t) const; +}; + +struct SharedPointerClientIdContentEqual : public std::binary_function, std::shared_ptr, bool> { + bool operator()(const std::shared_ptr& a, const std::shared_ptr& b) const; +}; + + +} // namespace std + + +#endif /* FUNCTIONALHASH_H_ */ diff --git a/src/CommonAPI/Event.h b/src/CommonAPI/Event.h index b032da9..9cac1dc 100644 --- a/src/CommonAPI/Event.h +++ b/src/CommonAPI/Event.h @@ -20,8 +20,8 @@ namespace CommonAPI { enum class SubscriptionStatus { - RETAIN, - CANCEL + RETAIN, + CANCEL }; /** @@ -29,33 +29,33 @@ enum class SubscriptionStatus { * * Class representing an event */ -template +template class Event { - public: - typedef std::tuple<_Arguments...> ArgumentsTuple; - typedef std::function Listener; - typedef std::function CancellableListener; - typedef std::list ListenersList; - typedef typename ListenersList::iterator Subscription; - - class CancellableListenerWrapper; - - /** - * \brief Subscribe a listener to this event - * - * Subscribe a listener to this event. - * ATTENTION: You should not build new proxies or register services in callbacks - * from events. This can cause a deadlock or assert. Instead, you should set a - * trigger for your application to do this on the next iteration of your event loop - * if needed. The preferred solution is to build all proxies you need at the - * beginning and react to events appropriatly for each. - * - * @param listener A listener to be added - * @return A token identifying this subscription - */ - inline Subscription subscribe(Listener listener); - - /** +public: + typedef std::tuple<_Arguments...> ArgumentsTuple; + typedef std::function Listener; + typedef std::function CancellableListener; + typedef std::list ListenersList; + typedef typename ListenersList::iterator Subscription; + + class CancellableListenerWrapper; + + /** + * \brief Subscribe a listener to this event + * + * Subscribe a listener to this event. + * ATTENTION: You should not build new proxies or register services in callbacks + * from events. This can cause a deadlock or assert. Instead, you should set a + * trigger for your application to do this on the next iteration of your event loop + * if needed. The preferred solution is to build all proxies you need at the + * beginning and react to events appropriatly for each. + * + * @param listener A listener to be added + * @return A token identifying this subscription + */ + virtual inline Subscription subscribe(Listener listener); + + /** * \brief Subscribe a cancellable listener to this event * * Subscribe a cancellable listener to this event @@ -68,119 +68,124 @@ class Event { * @param listener A cancellable listener to be added * @return A token identifying this subscription */ - Subscription subscribeCancellableListener(CancellableListener listener); + Subscription subscribeCancellableListener(CancellableListener listener); - /** + /** * \brief Remove a listener from this event * * Remove a listener from this event * Note: Do not call this inside a listener notification callback it will deadlock! Use cancellable listeners instead. * * @param listenerSubscription A listener token to be removed + * @return true, if the removed subscription was the last one */ - void unsubscribe(Subscription listenerSubscription); + void unsubscribe(Subscription listenerSubscription); - virtual ~Event() {} + virtual ~Event() { + } - protected: - // Returns false if all subscriptions were cancelled - // Does not send *Removed events! - SubscriptionStatus notifyListeners(const _Arguments&... eventArguments); +protected: + // Returns false if all subscriptions were cancelled + // Does not send *Removed events! + SubscriptionStatus notifyListeners(const _Arguments&... eventArguments); - // Events sent during subscribe() - virtual void onFirstListenerAdded(const CancellableListener& listener) { } - virtual void onListenerAdded(const CancellableListener& listener) { } + // Events sent during subscribe() + virtual void onFirstListenerAdded(const CancellableListener& listener) { + } + virtual void onListenerAdded(const CancellableListener& listener) { + } - // Events sent during unsubscribe() - virtual void onListenerRemoved(const CancellableListener& listener) { } - virtual void onLastListenerRemoved(const CancellableListener& listener) { } + // Events sent during unsubscribe() + virtual void onListenerRemoved(const CancellableListener& listener) { } + virtual void onLastListenerRemoved(const CancellableListener& listener) { } - inline bool hasListeners() const; + inline bool hasListeners() const; - private: - ListenersList listenersList_; - std::mutex listenerListMutex_; +//private: + ListenersList listenersList_; + std::mutex listenerListMutex_; }; -template +template class Event<_Arguments...>::CancellableListenerWrapper { - public: - CancellableListenerWrapper(Listener&& listener): listener_(std::move(listener)) { - } - - SubscriptionStatus operator()(const _Arguments&... eventArguments) { - listener_(eventArguments...); - return SubscriptionStatus::RETAIN; - } - - private: - Listener listener_; +public: + CancellableListenerWrapper(Listener&& listener) : + listener_(std::move(listener)) { + } + + SubscriptionStatus operator()(const _Arguments&... eventArguments) { + listener_(eventArguments...); + return SubscriptionStatus::RETAIN; + } + +private: + Listener listener_; }; -template +template typename Event<_Arguments...>::Subscription Event<_Arguments...>::subscribe(Listener listener) { - return subscribeCancellableListener(CancellableListenerWrapper(std::move(listener))); + return subscribeCancellableListener(CancellableListenerWrapper(std::move(listener))); } -template +template typename Event<_Arguments...>::Subscription Event<_Arguments...>::subscribeCancellableListener(CancellableListener listener) { listenerListMutex_.lock(); const bool firstListenerAdded = listenersList_.empty(); - listenersList_.emplace_front(std::move(listener)); - Subscription listenerSubscription = listenersList_.begin(); - listenerListMutex_.unlock(); + listenersList_.emplace_front(std::move(listener)); + Subscription listenerSubscription = listenersList_.begin(); + listenerListMutex_.unlock(); - if (firstListenerAdded) { - onFirstListenerAdded(*listenerSubscription); - } + if (firstListenerAdded) { + onFirstListenerAdded(*listenerSubscription); + } - onListenerAdded(*listenerSubscription); + onListenerAdded(*listenerSubscription); - return listenerSubscription; + return listenerSubscription; } -template +template void Event<_Arguments...>::unsubscribe(Subscription listenerSubscription) { - const CancellableListener cancellableListener = *listenerSubscription; + const CancellableListener cancellableListener = *listenerSubscription; - listenerListMutex_.lock(); - listenersList_.erase(listenerSubscription); - const bool lastListenerRemoved = listenersList_.empty(); - listenerListMutex_.unlock(); + listenerListMutex_.lock(); + listenersList_.erase(listenerSubscription); + const bool lastListenerRemoved = listenersList_.empty(); + listenerListMutex_.unlock(); - onListenerRemoved(cancellableListener); + onListenerRemoved(cancellableListener); - if (lastListenerRemoved) { - onLastListenerRemoved(cancellableListener); - } + if (lastListenerRemoved) { + onLastListenerRemoved(cancellableListener); + } } -template +template SubscriptionStatus Event<_Arguments...>::notifyListeners(const _Arguments&... eventArguments) { - listenerListMutex_.lock(); - for (auto iterator = listenersList_.begin(); iterator != listenersList_.end(); ) { - const CancellableListener& cancellableListener = *iterator; - const SubscriptionStatus listenerSubscriptionStatus = cancellableListener(eventArguments...); + listenerListMutex_.lock(); + for (auto iterator = listenersList_.begin(); iterator != listenersList_.end();) { + const CancellableListener& cancellableListener = *iterator; + const SubscriptionStatus listenerSubscriptionStatus = cancellableListener(eventArguments...); - if (listenerSubscriptionStatus == SubscriptionStatus::CANCEL) { - auto listenerIterator = iterator; - iterator++; - listenersList_.erase(listenerIterator); - } else - iterator++; - } + if (listenerSubscriptionStatus == SubscriptionStatus::CANCEL) { + auto listenerIterator = iterator; + iterator++; + listenersList_.erase(listenerIterator); + } else + iterator++; + } - const bool lEmpty = listenersList_.empty(); + const bool lEmpty = listenersList_.empty(); - listenerListMutex_.unlock(); + listenerListMutex_.unlock(); - return lEmpty ? SubscriptionStatus::CANCEL : SubscriptionStatus::RETAIN; + return lEmpty ? SubscriptionStatus::CANCEL : SubscriptionStatus::RETAIN; } -template +template bool Event<_Arguments...>::hasListeners() const { - return !listenersList_.empty(); + return !listenersList_.empty(); } } // namespace CommonAPI diff --git a/src/CommonAPI/SelectiveEvent.h b/src/CommonAPI/SelectiveEvent.h new file mode 100644 index 0000000..11612c3 --- /dev/null +++ b/src/CommonAPI/SelectiveEvent.h @@ -0,0 +1,38 @@ +/* Copyright (C) 2013 BMW Group + * Author: Manfred Bathelt (manfred.bathelt@bmw.de) + * Author: Juergen Gehring (juergen.gehring@bmw.de) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#if !defined (COMMONAPI_INTERNAL_COMPILATION) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#ifndef COMMONAPI_SELECTIVE_EVENT_H_ +#define COMMONAPI_SELECTIVE_EVENT_H_ + +#include "Event.h" + +namespace CommonAPI { + +template +class SelectiveEvent: public Event<_Arguments...> { +public: + typedef typename Event<_Arguments...>::Listener Listener; + typedef typename Event<_Arguments...>::Subscription Subscription; + + virtual ~SelectiveEvent() { + } + + Subscription subscribe(Listener listener) { + // just delegate + bool success; + return subscribe(listener, success); + } + virtual Subscription subscribe(Listener listener, bool& success) = 0; +}; + +} // namespace CommonAPI + +#endif diff --git a/src/CommonAPI/Stub.h b/src/CommonAPI/Stub.h index 22892f4..d724548 100644 --- a/src/CommonAPI/Stub.h +++ b/src/CommonAPI/Stub.h @@ -19,8 +19,9 @@ namespace CommonAPI { class StubAdapter { - public: - virtual ~StubAdapter() { } +public: + virtual ~StubAdapter() { + } virtual const std::string getAddress() const = 0; virtual const std::string& getDomain() const = 0; @@ -29,19 +30,26 @@ class StubAdapter { }; struct StubBase { - virtual ~StubBase() {} + virtual ~StubBase() { + } }; -template -class Stub : public StubBase { - static_assert(std::is_base_of::value, "Invalid StubAdapter Class!"); - public: - typedef _StubAdapter StubAdapterType; - typedef _StubRemoteEventHandler RemoteEventHandlerType; +template +class Stub: public StubBase { + static_assert(std::is_base_of::value, "Invalid StubAdapter Class!"); + public: + typedef _StubAdapter StubAdapterType; + typedef _StubRemoteEventHandler RemoteEventHandlerType; - virtual ~Stub() { } + virtual ~Stub() { + } - virtual _StubRemoteEventHandler* initStubAdapter(const std::shared_ptr<_StubAdapter>& stubAdapter) = 0; + virtual _StubRemoteEventHandler* initStubAdapter(const std::shared_ptr<_StubAdapter>& stubAdapter) = 0; +}; + +enum SelectiveBroadcastSubscriptionEvent { + SUBSCRIBED, + UNSUBSCRIBED }; } // namespace CommonAPI diff --git a/src/CommonAPI/types.h b/src/CommonAPI/types.h index f8663f1..ffc338c 100644 --- a/src/CommonAPI/types.h +++ b/src/CommonAPI/types.h @@ -13,6 +13,12 @@ #define COMMONAPI_TYPES_H_ #include +#include +#include +#include +#include +#include "ContainerUtils.h" +#include "Event.h" #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) # define COMMONAPI_DEPRECATED __attribute__ ((__deprecated__)) @@ -61,7 +67,22 @@ class ClientId { public: virtual ~ClientId() { } virtual bool operator==(ClientId& clientIdToCompare) = 0; + virtual std::size_t hashCode() = 0; }; + +template +struct SelectiveBroadcastFunctorHelper { + typedef std::function SelectiveBroadcastFunctor; +}; + + +typedef std::unordered_set, SharedPointerClientIdContentHash, SharedPointerClientIdContentEqual> ClientIdList; +template +struct SelectiveBroadcastSubscriptionResult { + typedef std::tuple::Subscription> SubscriptionResult; + +}; + } // namespace CommonAPI #endif // COMMONAPI_TYPES_H_ -- cgit v1.2.1