summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJürgen Gehring <juergen.gehring@bmw.de>2015-07-28 06:46:54 -0700
committerJürgen Gehring <juergen.gehring@bmw.de>2015-07-28 06:46:54 -0700
commit3d2fb21d0e93b6b595610285e910ac80c099a174 (patch)
tree56265166864b3ce52ef713f827d4f580ec38f667
parent56d1059459c24971bcbf45adef60f6dfd0b44667 (diff)
downloadgenivi-common-api-runtime-3d2fb21d0e93b6b595610285e910ac80c099a174.tar.gz
CommonAPI 3.1.3
-rw-r--r--CMakeLists.txt6
-rw-r--r--NEWS14
-rw-r--r--README3
-rw-r--r--cmake/CommonAPIConfigVersion.cmake.in2
-rw-r--r--include/CommonAPI/AttributeExtension.hpp17
-rw-r--r--include/CommonAPI/CommonAPI.hpp1
-rw-r--r--include/CommonAPI/Event.hpp150
-rw-r--r--include/CommonAPI/Extensions/AttributeCacheExtension.hpp129
-rw-r--r--include/CommonAPI/Logger.hpp19
-rw-r--r--include/CommonAPI/MainLoopContext.hpp9
-rw-r--r--src/CommonAPI/Logger.cpp11
-rw-r--r--src/CommonAPI/Runtime.cpp19
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" )
diff --git a/NEWS b/NEWS
deleted file mode 100644
index 2b61002..0000000
--- a/NEWS
+++ /dev/null
@@ -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
diff --git a/README b/README
new file mode 100644
index 0000000..3527542
--- /dev/null
+++ b/README
@@ -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(), '.', '_');