diff options
author | Jürgen Gehring <juergen.gehring@bmw.de> | 2015-07-28 06:46:54 -0700 |
---|---|---|
committer | Jürgen Gehring <juergen.gehring@bmw.de> | 2015-07-28 06:46:54 -0700 |
commit | 3d2fb21d0e93b6b595610285e910ac80c099a174 (patch) | |
tree | 56265166864b3ce52ef713f827d4f580ec38f667 | |
parent | 56d1059459c24971bcbf45adef60f6dfd0b44667 (diff) | |
download | genivi-common-api-runtime-3d2fb21d0e93b6b595610285e910ac80c099a174.tar.gz |
CommonAPI 3.1.3
-rw-r--r-- | CMakeLists.txt | 6 | ||||
-rw-r--r-- | NEWS | 14 | ||||
-rw-r--r-- | README | 3 | ||||
-rw-r--r-- | cmake/CommonAPIConfigVersion.cmake.in | 2 | ||||
-rw-r--r-- | include/CommonAPI/AttributeExtension.hpp | 17 | ||||
-rw-r--r-- | include/CommonAPI/CommonAPI.hpp | 1 | ||||
-rw-r--r-- | include/CommonAPI/Event.hpp | 150 | ||||
-rw-r--r-- | include/CommonAPI/Extensions/AttributeCacheExtension.hpp | 129 | ||||
-rw-r--r-- | include/CommonAPI/Logger.hpp | 19 | ||||
-rw-r--r-- | include/CommonAPI/MainLoopContext.hpp | 9 | ||||
-rw-r--r-- | src/CommonAPI/Logger.cpp | 11 | ||||
-rw-r--r-- | src/CommonAPI/Runtime.cpp | 19 |
12 files changed, 274 insertions, 106 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 4711294..52eac34 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ PROJECT(libcommonapi) # version of CommonAPI SET( LIBCOMMONAPI_MAJOR_VERSION 3 ) SET( LIBCOMMONAPI_MINOR_VERSION 1 ) -SET( LIBCOMMONAPI_PATCH_VERSION 2 ) +SET( LIBCOMMONAPI_PATCH_VERSION 3 ) message(STATUS "Project name: ${PROJECT_NAME}") @@ -64,7 +64,7 @@ set(INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation director foreach(p LIB INCLUDE CMAKE) set(var INSTALL_${p}_DIR) if(NOT IS_ABSOLUTE "${${var}}") - set(${var} "${CMAKE_INSTALL_PREFIX}/${${var}}") + set(ABSOLUTE_${var} "${CMAKE_INSTALL_PREFIX}/${${var}}") endif() endforeach() @@ -143,7 +143,7 @@ export(TARGETS CommonAPI export(PACKAGE CommonAPI) # Create the CommonAPIConfig.cmake and CommonAPIConfigVersion files ... -file(RELATIVE_PATH REL_INCLUDE_DIR "${INSTALL_CMAKE_DIR}" "${INSTALL_INCLUDE_DIR}") +file(RELATIVE_PATH REL_INCLUDE_DIR "${ABSOLUTE_INSTALL_CMAKE_DIR}" "${ABSOLUTE_INSTALL_INCLUDE_DIR}") # ... for the build tree set(CONF_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/include" ) @@ -1,14 +0,0 @@ -This is CommonAPI 3.1.0 - -Changes since 3.0.1 -- Windows support updated -- CommonAPI logger added -- Bugfix for ByteBuffers -- GTEST_ROOT must be set as DEFINE instead of environment variable - -Changes since 2.1.6 -- Support for asynchronous stubs -- Subscribe/Unsubscribe is now thread safe -- Full support for deployable serialization -- Dynamic loading of bindings -- Simplified application interface for building proxies and stubs @@ -0,0 +1,3 @@ +This is CommonAPI 3.1.3 + +Please refer to INSTALL for further information.
\ No newline at end of file diff --git a/cmake/CommonAPIConfigVersion.cmake.in b/cmake/CommonAPIConfigVersion.cmake.in index 9d6ff4f..5fd8813 100644 --- a/cmake/CommonAPIConfigVersion.cmake.in +++ b/cmake/CommonAPIConfigVersion.cmake.in @@ -3,7 +3,7 @@ set(PACKAGE_VERSION "@PACKAGE_VERSION@") set(PACKAGE_VERSION_COMPATIBLE FALSE) string(REPLACE "." "\\." ESCAPED_API_HEADER_VERSION "@COMMONAPI_API_HEADER_VERSION@") -if("${PACKAGE_FIND_VERSION}" MATCHES "^@ESCAPED_API_HEADER_VERSION@($|\\.)") +if("${PACKAGE_FIND_VERSION}" MATCHES "^${ESCAPED_API_HEADER_VERSION}($|\\.)") set(PACKAGE_VERSION_COMPATIBLE TRUE) endif() diff --git a/include/CommonAPI/AttributeExtension.hpp b/include/CommonAPI/AttributeExtension.hpp index aee1f8d..cc26723 100644 --- a/include/CommonAPI/AttributeExtension.hpp +++ b/include/CommonAPI/AttributeExtension.hpp @@ -4,7 +4,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. #if !defined (COMMONAPI_INTERNAL_COMPILATION) -#error "Only <CommonAPI/CommonAPI.h> can be included directly, this file may disappear or change contents." +#error "Only <CommonAPI/CommonAPI.hpp> can be included directly, this file may disappear or change contents." #endif #ifndef COMMON_API_DBUS_ATTRIBUTE_EXTENSION_HPP_ @@ -17,10 +17,6 @@ #include <CommonAPI/Event.hpp> #include <CommonAPI/Types.hpp> -#ifdef WIN32 -#include "Attribute.hpp" -#endif - namespace CommonAPI { template<typename _AttributeType> @@ -47,17 +43,6 @@ std::shared_ptr< > createProxyWithDefaultAttributeExtension( const std::string &_domain, const std::string &_instance); -#ifdef WIN32 -template<typename _AttributeType> -class WINDummyAttributeExtension : public CommonAPI::AttributeExtension<_AttributeType> { - typedef AttributeExtension<_AttributeType> __baseClass_t; - WINDummyAttribute dummyAttribute; -public: - WINDummyAttributeExtension() {}; - ~WINDummyAttributeExtension() {} -}; -#endif - } // namespace CommonAPI #endif // COMMON_API_DBUS_ATTRIBUTE_EXTENSION_HPP_ diff --git a/include/CommonAPI/CommonAPI.hpp b/include/CommonAPI/CommonAPI.hpp index 5568330..81748d1 100644 --- a/include/CommonAPI/CommonAPI.hpp +++ b/include/CommonAPI/CommonAPI.hpp @@ -11,6 +11,7 @@ #endif #include "Address.hpp" +#include "Attribute.hpp" #include "AttributeExtension.hpp" #include "ByteBuffer.hpp" #include "MainLoopContext.hpp" diff --git a/include/CommonAPI/Event.hpp b/include/CommonAPI/Event.hpp index 982f9a3..d56ea4b 100644 --- a/include/CommonAPI/Event.hpp +++ b/include/CommonAPI/Event.hpp @@ -66,14 +66,15 @@ public: protected: void notifyListeners(const _Arguments&... eventArguments); + void notifySpecificListener(const Subscription subscription, const _Arguments&... eventArguments); virtual void onFirstListenerAdded(const Listener& listener) {} - virtual void onListenerAdded(const Listener& listener) {} + virtual void onListenerAdded(const Listener& listener, const Subscription subscription) {} virtual void onListenerRemoved(const Listener& listener) {} virtual void onLastListenerRemoved(const Listener& listener) {} -//private: +private: ListenersMap subscriptions_; Subscription nextSubscription_; @@ -86,80 +87,113 @@ protected: template<typename ... _Arguments> typename Event<_Arguments...>::Subscription Event<_Arguments...>::subscribe(Listener listener) { - Subscription subscription; - bool isFirstListener; + Subscription subscription; + bool isFirstListener; - subscriptionMutex_.lock(); - subscription = nextSubscription_++; - // TODO?: check for key/subscription overrun - listener = pendingSubscriptions_[subscription] = std::move(listener); - isFirstListener = (0 == subscriptions_.size()); - subscriptionMutex_.unlock(); + subscriptionMutex_.lock(); + subscription = nextSubscription_++; + // TODO?: check for key/subscription overrun + listener = pendingSubscriptions_[subscription] = std::move(listener); + isFirstListener = (0 == subscriptions_.size()); + subscriptionMutex_.unlock(); - if (isFirstListener) - onFirstListenerAdded(listener); - onListenerAdded(listener); + if (isFirstListener) + onFirstListenerAdded(listener); + onListenerAdded(listener, subscription); - return subscription; + return subscription; } template<typename ... _Arguments> void Event<_Arguments...>::unsubscribe(Subscription subscription) { - bool isLastListener(false); - bool hasUnsubscribed(false); + bool isLastListener(false); + bool hasUnsubscribed(false); + Listener listener; + + subscriptionMutex_.lock(); + auto listenerIterator = subscriptions_.find(subscription); + if (subscriptions_.end() != listenerIterator + && pendingUnsubscriptions_.end() == pendingUnsubscriptions_.find(subscription)) { + listener = listenerIterator->second; + pendingUnsubscriptions_.insert(subscription); + isLastListener = (1 == subscriptions_.size()); + hasUnsubscribed = true; + } + else { + listenerIterator = pendingSubscriptions_.find(subscription); + if (pendingSubscriptions_.end() != listenerIterator) { + listener = listenerIterator->second; + pendingSubscriptions_.erase(listenerIterator); + isLastListener = (0 == subscriptions_.size()); + hasUnsubscribed = true; + } + } + subscriptionMutex_.unlock(); - subscriptionMutex_.lock(); - auto listener = subscriptions_.find(subscription); - if (subscriptions_.end() != listener - && pendingUnsubscriptions_.end() == pendingUnsubscriptions_.find(subscription)) { - pendingUnsubscriptions_.insert(subscription); - isLastListener = (1 == subscriptions_.size()); - hasUnsubscribed = true; - } - else { - listener = pendingSubscriptions_.find(subscription); - if (pendingSubscriptions_.end() != listener) { - pendingSubscriptions_.erase(subscription); - isLastListener = (0 == subscriptions_.size()); - hasUnsubscribed = true; - } - } - subscriptionMutex_.unlock(); - - if (hasUnsubscribed) { - onListenerRemoved(listener->second); - if (isLastListener) { - onLastListenerRemoved(listener->second); - } - } + if (hasUnsubscribed) { + onListenerRemoved(listener); + if (isLastListener) { + onLastListenerRemoved(listener); + } + } } template<typename ... _Arguments> void Event<_Arguments...>::notifyListeners(const _Arguments&... eventArguments) { - subscriptionMutex_.lock(); - notificationMutex_.lock(); - for (auto iterator = pendingUnsubscriptions_.begin(); - iterator != pendingUnsubscriptions_.end(); - iterator++) { - subscriptions_.erase(*iterator); - } - pendingUnsubscriptions_.clear(); - - for (auto iterator = pendingSubscriptions_.begin(); - iterator != pendingSubscriptions_.end(); - iterator++) { - subscriptions_.insert(*iterator); - } - pendingSubscriptions_.clear(); - - subscriptionMutex_.unlock(); - for (auto iterator = subscriptions_.begin(); iterator != subscriptions_.end(); iterator++) { + subscriptionMutex_.lock(); + notificationMutex_.lock(); + for (auto iterator = pendingUnsubscriptions_.begin(); + iterator != pendingUnsubscriptions_.end(); + iterator++) { + subscriptions_.erase(*iterator); + } + pendingUnsubscriptions_.clear(); + + for (auto iterator = pendingSubscriptions_.begin(); + iterator != pendingSubscriptions_.end(); + iterator++) { + subscriptions_.insert(*iterator); + } + pendingSubscriptions_.clear(); + + subscriptionMutex_.unlock(); + for (auto iterator = subscriptions_.begin(); iterator != subscriptions_.end(); iterator++) { iterator->second(eventArguments...); } notificationMutex_.unlock(); } +template<typename ... _Arguments> +void Event<_Arguments...>::notifySpecificListener(const Subscription subscription, const _Arguments&... eventArguments) { + subscriptionMutex_.lock(); + notificationMutex_.lock(); + for (auto iterator = pendingUnsubscriptions_.begin(); + iterator != pendingUnsubscriptions_.end(); + iterator++) { + subscriptions_.erase(*iterator); + } + pendingUnsubscriptions_.clear(); + + for (auto iterator = pendingSubscriptions_.begin(); + iterator != pendingSubscriptions_.end(); + iterator++) { + + subscriptions_.insert(*iterator); + } + pendingSubscriptions_.clear(); + + + subscriptionMutex_.unlock(); + for (auto iterator = subscriptions_.begin(); iterator != subscriptions_.end(); iterator++) { + if (subscription == iterator->first) { + iterator->second(eventArguments...); + } + } + + notificationMutex_.unlock(); +} + } // namespace CommonAPI #endif // COMMONAPI_EVENT_HPP_ diff --git a/include/CommonAPI/Extensions/AttributeCacheExtension.hpp b/include/CommonAPI/Extensions/AttributeCacheExtension.hpp new file mode 100644 index 0000000..92bced6 --- /dev/null +++ b/include/CommonAPI/Extensions/AttributeCacheExtension.hpp @@ -0,0 +1,129 @@ +// Copyright (C) 2015 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// 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/. + +#ifndef COMMONAPI_EXTENSIONS_ATTRIBUTE_CACHE_EXTENSION_HPP_ +#define COMMONAPI_EXTENSIONS_ATTRIBUTE_CACHE_EXTENSION_HPP_ + +#include <CommonAPI/CommonAPI.hpp> + +#include <cassert> +#include <memory> +#include <type_traits> + +namespace CommonAPI { +namespace Extensions { + +template<typename _AttributeType, + bool = (std::is_base_of< + CommonAPI::ObservableAttribute< + typename _AttributeType::ValueType>, + _AttributeType>::value + || std::is_base_of< + CommonAPI::ObservableReadonlyAttribute< + typename _AttributeType::ValueType>, + _AttributeType>::value)> +class AttributeCacheExtension { +}; + +template<typename _AttributeType> +class AttributeCacheExtension<_AttributeType, false> : public CommonAPI::AttributeExtension< + _AttributeType> { +protected: + typedef CommonAPI::AttributeExtension<_AttributeType> __baseClass_t; + + typedef typename _AttributeType::ValueType value_t; + + AttributeCacheExtension(_AttributeType& baseAttribute) + : CommonAPI::AttributeExtension<_AttributeType>(baseAttribute) { + } + + ~AttributeCacheExtension() { + } +}; + +template<typename _AttributeType> +class AttributeCacheExtension<_AttributeType, true> : public CommonAPI::AttributeExtension< + _AttributeType> { + typedef CommonAPI::AttributeExtension<_AttributeType> __baseClass_t; + +protected: + typedef typename _AttributeType::ValueType value_t; + typedef std::shared_ptr<const value_t> valueptr_t; + + AttributeCacheExtension(_AttributeType& baseAttribute) + : CommonAPI::AttributeExtension<_AttributeType>(baseAttribute) { + auto &event = __baseClass_t::getBaseAttribute().getChangedEvent(); + subscription_ = + event.subscribe( + std::bind( + &AttributeCacheExtension<_AttributeType, true>::onValueUpdate, + this, std::placeholders::_1)); + } + + ~AttributeCacheExtension() { + auto &event = __baseClass_t::getBaseAttribute().getChangedEvent(); + event.unsubscribe(subscription_); + } + +public: + /** + * @brief getCachedValue Retrieve attribute value from the cache + * @return The value of the attribute or a null pointer if the value is not + * yet available. Retrieving a non-cached value will trigger + * retrieval of the value. Changes to the cached value are emitted + * via the getChangedEvent. + */ + valueptr_t getCachedValue() { + if (cachedValue_) { + return cachedValue_; + } + + // This may get called more than once if a previous retrieval is still + // on-going (saving the current state would just take up extra resources) + __baseClass_t::getBaseAttribute().getValueAsync( + std::bind(&AttributeCacheExtension<_AttributeType, true>::valueRetrieved, + this, std::placeholders::_1, std::placeholders::_2)); + + return nullptr; + } + + /** + * @brief getCachedValue Retrieve attribute value from the cache returning a + * default value if the cache was empty. + * @param errorValue The value to return if the value could not be found in + * the cache. + * @return The value of the attribute or errorValue. + */ + valueptr_t getCachedValue(const value_t &errorValue) { + valueptr_t result = getCachedValue(); + + if (!result) + result = std::make_shared<const value_t>(errorValue); + + return result; + } + +private: + + void valueRetrieved(const CommonAPI::CallStatus &callStatus, value_t t) { + if (callStatus == CommonAPI::CallStatus::SUCCESS) { + assert(!cachedValue_ || *cachedValue_ == t); + onValueUpdate(t); + } + } + + void onValueUpdate(const value_t& t) { + cachedValue_ = std::make_shared<const value_t>(t); + } + + valueptr_t cachedValue_; + + typename _AttributeType::ChangedEvent::Subscription subscription_; +}; + +} // namespace Extensions +} // namespace CommonAPI + +#endif // COMMONAPI_EXTENSIONS_ATTRIBUTE_CACHE_EXTENSION_HPP_ diff --git a/include/CommonAPI/Logger.hpp b/include/CommonAPI/Logger.hpp index d2761ac..2247ea1 100644 --- a/include/CommonAPI/Logger.hpp +++ b/include/CommonAPI/Logger.hpp @@ -120,20 +120,25 @@ public: }; COMMONAPI_EXPORT Logger(); + COMMONAPI_EXPORT ~Logger(); template<typename... _LogEntries> COMMONAPI_EXPORT static void log(Level _level, _LogEntries... _entries) { - std::stringstream buffer; - log_intern(buffer, _entries...); - Logger::get()->doLog(_level, buffer.str()); +#if defined(USE_CONSOLE) || defined(USE_FILE) || defined(USE_DLT) + if (_level < maximumLogLevel_) { + std::stringstream buffer; + log_intern(buffer, _entries...); + Logger::get()->doLog(_level, buffer.str()); + } +#endif } - COMMONAPI_EXPORT static void init(bool, const std::string &, bool = false, const std::string & = ""); + COMMONAPI_EXPORT static void init(bool, const std::string &, bool, const std::string &); private: - COMMONAPI_EXPORT static inline std::shared_ptr<Logger> get() { - static std::shared_ptr<Logger> theLogger = std::make_shared<Logger>(); - return theLogger; + COMMONAPI_EXPORT static inline Logger *get() { + static Logger theLogger; + return &theLogger; } COMMONAPI_EXPORT static void log_intern(std::stringstream &_buffer) { diff --git a/include/CommonAPI/MainLoopContext.hpp b/include/CommonAPI/MainLoopContext.hpp index b2e1056..4487292 100644 --- a/include/CommonAPI/MainLoopContext.hpp +++ b/include/CommonAPI/MainLoopContext.hpp @@ -111,6 +111,15 @@ struct Watch { */ virtual const pollfd& getAssociatedFileDescriptor() = 0; +#ifdef WIN32 + /** + * \brief Returns the event bound to the file descriptor that is managed by this watch. + * + * @return The event bound to the associated file descriptor. + */ + virtual const HANDLE& getAssociatedEvent() = 0; +#endif + /** * \brief Returns a vector of all dispatch sources that depend on the watched file descriptor. * diff --git a/src/CommonAPI/Logger.cpp b/src/CommonAPI/Logger.cpp index 4514bd7..f7e2de3 100644 --- a/src/CommonAPI/Logger.cpp +++ b/src/CommonAPI/Logger.cpp @@ -39,6 +39,13 @@ Logger::Logger() { #endif } +Logger::~Logger() { +#ifdef USE_DLT + DLT_UNREGISTER_CONTEXT(dlt_); + DLT_UNREGISTER_APP(); +#endif +} + void Logger::init(bool _useConsole, const std::string &_fileName, bool _useDlt, const std::string &_level) { #ifdef USE_CONSOLE @@ -63,13 +70,13 @@ void Logger::doLog(Level _level, const std::string &_message) { #ifdef USE_CONSOLE if (useConsole_) { - std::lock_guard<std::mutex> consoleGuard(mutex_); + std::lock_guard<std::mutex> itsLock(mutex_); std::cout << "[CAPI][" << levelAsString(_level) << "] " << _message << std::endl; } #endif #ifdef USE_FILE if (file_ && file_->is_open()) { - std::lock_guard<std::mutex> consoleGuard(mutex_); + std::lock_guard<std::mutex> itsLock(mutex_); (*(file_.get())) << "[CAPI][" << levelAsString(_level) << "] " << _message << std::endl; } #endif diff --git a/src/CommonAPI/Runtime.cpp b/src/CommonAPI/Runtime.cpp index 74c2c0f..9cd73eb 100644 --- a/src/CommonAPI/Runtime.cpp +++ b/src/CommonAPI/Runtime.cpp @@ -153,6 +153,11 @@ Runtime::readConfiguration() { if (!reader.load(config)) return false; + std::string itsConsole("true"); + std::string itsFile; + std::string itsDlt("false"); + std::string itsLevel("info"); + std::shared_ptr<IniFileReader::Section> section = reader.getSection("logging"); if (section) { @@ -160,13 +165,13 @@ Runtime::readConfiguration() { std::string itsFile = section->getValue("file"); std::string itsDlt = section->getValue("dlt"); std::string itsLevel = section->getValue("level"); - - Logger::init((itsConsole == "true"), - itsFile, - (itsDlt == "true"), - itsLevel); } + Logger::init((itsConsole == "true"), + itsFile, + (itsDlt == "true"), + itsLevel); + section = reader.getSection("default"); if (section) { std::string binding = section->getValue("binding"); @@ -298,7 +303,11 @@ Runtime::getLibrary( // name. library = getProperty("LibraryBase"); if (library != "") { +#ifdef WIN32 + library = library + "-" + defaultBinding_; +#else library = "lib" + library + "-" + defaultBinding_; +#endif } else { library = "lib" + _domain + "__" + _interface + "__" + _instance; std::replace(library.begin(), library.end(), '.', '_'); |