summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAleksandar Kanchev <kanchev@itestra.com>2013-07-24 09:50:18 +0200
committerGerrit Code Review <qqmthk1@lpmodthk02.bmwgroup.net>2013-07-24 09:50:18 +0200
commit4accbb4a2c1bcefe15c7aa3e698c0ff79ed8fdac (patch)
tree9ddacb6e4068c56680186ca22b4396d8826ee803 /src
parentbe1761cff29995a03337319effcadb07b34cde30 (diff)
parent751e239d58f7382799561190369aa7b480dc6db3 (diff)
downloadgenivi-common-api-runtime-4accbb4a2c1bcefe15c7aa3e698c0ff79ed8fdac.tar.gz
Merge "Introduced dynamic loading of middleware bindings and other generic libraries."
Diffstat (limited to 'src')
-rw-r--r--src/CommonAPI/CommonAPI.h1
-rw-r--r--src/CommonAPI/Configuration.cpp166
-rw-r--r--src/CommonAPI/Configuration.h121
-rw-r--r--src/CommonAPI/Factory.h1
-rw-r--r--src/CommonAPI/Factory.hpp10
-rw-r--r--src/CommonAPI/MiddlewareInfo.h17
-rw-r--r--src/CommonAPI/Runtime.cpp334
-rw-r--r--src/CommonAPI/Runtime.h98
-rw-r--r--src/CommonAPI/utils.h340
9 files changed, 1033 insertions, 55 deletions
diff --git a/src/CommonAPI/CommonAPI.h b/src/CommonAPI/CommonAPI.h
index f72d1d2..e9beb77 100644
--- a/src/CommonAPI/CommonAPI.h
+++ b/src/CommonAPI/CommonAPI.h
@@ -14,6 +14,7 @@
#include "Runtime.h"
#include "Factory.h"
#include "AttributeExtension.h"
+#include "ByteBuffer.h"
#include "types.h"
#undef COMMONAPI_INTERNAL_COMPILATION
diff --git a/src/CommonAPI/Configuration.cpp b/src/CommonAPI/Configuration.cpp
new file mode 100644
index 0000000..470015d
--- /dev/null
+++ b/src/CommonAPI/Configuration.cpp
@@ -0,0 +1,166 @@
+/* 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 <fstream>
+
+#include "Configuration.h"
+#include "utils.h"
+
+
+namespace CommonAPI {
+
+std::unordered_map<std::string, std::string> knownMiddlewareAliases_;
+std::unordered_map<std::string, std::string> knownMiddlewarePaths_;
+std::unordered_map<std::string, std::vector<std::string> > knownGeneratedPaths_;
+std::vector<std::string> librarySearchPaths_;
+std::string defaultBindingIdentifier_ = "";
+
+
+const Configuration& Configuration::getInstance() {
+ static Configuration* instance = NULL;
+ if (!instance) {
+ instance = new Configuration();
+ instance->retrieveCommonApiConfiguration();
+ }
+ return *instance;
+}
+
+const std::vector<std::string>& Configuration::getLibrarySearchPaths() const {
+ return librarySearchPaths_;
+}
+
+const std::string& Configuration::getMiddlewareNameForAlias(const std::string& alias) const {
+ auto foundMiddlewareName = knownMiddlewareAliases_.find(alias);
+ if (foundMiddlewareName != knownMiddlewareAliases_.end()) {
+ return foundMiddlewareName->second;
+ } else {
+ return alias;
+ }
+}
+
+const std::string& Configuration::getMiddlewareLibraryPath(const std::string& middlewareIdentifier) const {
+ auto foundMiddlewarePath = knownMiddlewarePaths_.find(middlewareIdentifier);
+ if (foundMiddlewarePath == knownMiddlewarePaths_.end()) {
+ static const std::string emptyReturn = "";
+ return emptyReturn;
+ }
+ return foundMiddlewarePath->second;
+}
+
+const std::vector<std::string>& Configuration::getGenericLibraryPaths(const std::string& middlewareIdentifier) const {
+ const auto& generatedPathsForMiddleware = knownGeneratedPaths_.find(middlewareIdentifier);
+ if (generatedPathsForMiddleware != knownGeneratedPaths_.end()) {
+ return generatedPathsForMiddleware->second;
+ }
+ static const std::vector<std::string> emptyReturn;
+ return emptyReturn;
+}
+
+const std::string& Configuration::getDefaultMiddlewareIdentifier() const {
+ return defaultBindingIdentifier_;
+}
+
+void Configuration::readConfigFile(std::ifstream& addressConfigFile) {
+ std::string currentlyParsedBindingIdentifier = "";
+ bool endFile = false;
+
+ std::string readLine;
+
+ while (addressConfigFile.good()) {
+ getline(addressConfigFile, readLine);
+ const size_t readLineLength = readLine.length();
+
+ if (strncmp(readLine.c_str(), CATEGORY_IDENTIFIER_BINDING, strlen(CATEGORY_IDENTIFIER_BINDING)) == 0
+ && readLine[readLineLength - 1] == CATEGORY_ENDING) {
+
+ std::string newBindingIdentifier = readLine.substr(
+ strlen(CATEGORY_IDENTIFIER_BINDING),
+ readLineLength - (strlen(CATEGORY_IDENTIFIER_BINDING) + 1));
+
+ trim(newBindingIdentifier);
+ if (containsOnlyAlphanumericCharacters(newBindingIdentifier)) {
+ currentlyParsedBindingIdentifier = newBindingIdentifier;
+ }
+
+ } else if (currentlyParsedBindingIdentifier != "") {
+ std::vector<std::string> parameterElements = split(readLine, '=');
+ if (parameterElements.size() == 2) {
+
+ if (parameterElements.at(0) == BINDING_PARAMETER_ALIAS) {
+ std::vector<std::string> aliases = split(parameterElements.at(1), ':');
+ for (const std::string& singleAlias: aliases) {
+ knownMiddlewareAliases_.insert( {singleAlias, currentlyParsedBindingIdentifier});
+ }
+
+ } else if (parameterElements.at(0) == BINDING_PARAMETER_LIBPATH) {
+ knownMiddlewarePaths_.insert( {currentlyParsedBindingIdentifier, parameterElements.at(1)});
+
+ } else if (parameterElements.at(0) == BINDING_PARAMETER_GENPATH) {
+ std::vector<std::string> paths = split(parameterElements.at(1), ':');
+ auto alreadyKnownPaths = knownGeneratedPaths_.find(currentlyParsedBindingIdentifier);
+
+ if (alreadyKnownPaths == knownGeneratedPaths_.end()) {
+ const std::vector<std::string> pathSet(paths.begin(), paths.end());
+ knownGeneratedPaths_.insert( {currentlyParsedBindingIdentifier, std::move(pathSet)} );
+ } else {
+ alreadyKnownPaths->second.insert(alreadyKnownPaths->second.end(), paths.begin(), paths.end());
+ }
+ }
+
+ } else if (parameterElements.size() == 1) {
+ if (parameterElements.at(0) == BINDING_PARAMETER_DEFAULT && defaultBindingIdentifier_ == "") {
+ defaultBindingIdentifier_ = currentlyParsedBindingIdentifier;
+ }
+ }
+ }
+ }
+}
+
+
+void Configuration::readEnvironmentVariables() {
+ librarySearchPaths_ = split(COMMONAPI_STD_LIB_PATH, ':');
+
+ const char* environmentBindingPath = getenv(COMMONAPI_ENVIRONMENT_BINDING_PATH);
+ if (environmentBindingPath) {
+ std::vector<std::string> environmentPaths = split(environmentBindingPath, ':');
+ librarySearchPaths_.insert(librarySearchPaths_.begin(), environmentPaths.begin(), environmentPaths.end());
+ }
+}
+
+
+void Configuration::retrieveCommonApiConfiguration() {
+ readEnvironmentVariables();
+
+ std::string fqnOfConfigFile = getCurrentBinaryFileFQN();
+ fqnOfConfigFile += COMMONAPI_CONFIG_SUFFIX;
+
+ std::ifstream commonapiConfigFile;
+ commonapiConfigFile.open(fqnOfConfigFile.c_str());
+
+ if (commonapiConfigFile.is_open()) {
+ readConfigFile(commonapiConfigFile);
+ commonapiConfigFile.close();
+ }
+
+ commonapiConfigFile.clear();
+ std::vector<std::string> splittedConfigFQN = split(fqnOfConfigFile, '/');
+ std::string globalConfigFQN = COMMONAPI_GLOBAL_CONFIG_ROOT + splittedConfigFQN.at(splittedConfigFQN.size() - 1);
+ commonapiConfigFile.open(globalConfigFQN);
+ if (commonapiConfigFile.is_open()) {
+ readConfigFile(commonapiConfigFile);
+ commonapiConfigFile.close();
+ }
+ commonapiConfigFile.clear();
+
+ commonapiConfigFile.open(COMMONAPI_GLOBAL_CONFIG_FQN);
+ if (commonapiConfigFile.is_open()) {
+ readConfigFile(commonapiConfigFile);
+ commonapiConfigFile.close();
+ }
+}
+
+
+} // namespace CommonAPI
diff --git a/src/CommonAPI/Configuration.h b/src/CommonAPI/Configuration.h
new file mode 100644
index 0000000..554518e
--- /dev/null
+++ b/src/CommonAPI/Configuration.h
@@ -0,0 +1,121 @@
+/* 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/. */
+
+#ifndef COMMONAPI_CONFIGURATION_H_
+#define COMMONAPI_CONFIGURATION_H_
+
+
+#include <unordered_map>
+#include <vector>
+#include <string>
+#include <cstring>
+
+
+namespace CommonAPI {
+
+
+static const char COMMONAPI_CONFIG_SUFFIX[] = ".conf";
+static const char COMMONAPI_GLOBAL_CONFIG_ROOT[] = "/etc/CommonAPI/";
+static const char COMMONAPI_GLOBAL_CONFIG_FQN[] = "/etc/CommonAPI/CommonAPI.conf";
+
+static const char COMMONAPI_STD_LIB_PATH[] = "/usr/lib:/usr/local/lib/";
+static const char COMMONAPI_ENVIRONMENT_BINDING_PATH[] = "COMMONAPI_BINDING_PATH";
+
+static const char CATEGORY_ENDING = '}';
+
+static const char CATEGORY_IDENTIFIER_BINDING[] = "{binding:";
+
+static const char BINDING_PARAMETER_ALIAS[] = "alias";
+static const char BINDING_PARAMETER_LIBPATH[] = "libpath";
+static const char BINDING_PARAMETER_GENPATH[] = "genpath";
+static const char BINDING_PARAMETER_DEFAULT[] = "default";
+
+
+/**
+ * Represents the contents of all parsed CommonAPI Configuration files.
+ *
+ * For more information on how to configure CommonAPI, see attached documentation.
+ */
+class Configuration {
+ public:
+ /**
+ * Returns the instance of the Configuration.
+ *
+ * When first calling this method, all configuration files that are found are parsed and
+ * the values are stored within this class.
+ *
+ * @return The singleton instance of the CommonAPI Configuration.
+ */
+ static const Configuration& getInstance();
+
+ Configuration(const Configuration&) = delete;
+ Configuration& operator=(const Configuration&) = delete;
+ Configuration(Configuration&&) = delete;
+ Configuration& operator=(Configuration&&) = delete;
+
+ /**
+ * Returns the search paths on which binding specific libraries may be found.
+ *
+ * Default search paths are /usr/lib and /usr/local/lib, those two will always be returned.
+ * If additional search paths have been configured, those will also be returned.
+ *
+ * @return
+ */
+ const std::vector<std::string>& getLibrarySearchPaths() const;
+
+ /**
+ * Returns the actual middleware identifier for the given alias.
+ *
+ * If no such alias has been configured, the given alias itself will be returned.
+ *
+ * @return The middleware identifier or the given alias itself, if no mapping to a middleware identifier was found.
+ */
+ const std::string& getMiddlewareNameForAlias(const std::string& alias) const;
+
+ /**
+ * Returns the specified library path for the given middleware identifier.
+ *
+ * If a path to a specific library has been configured for the given middleware identifier, this path will be returned.
+ * If no such path has been configured, the empty string will be returned.
+ *
+ * @return The path to the middleware library, if any is known, the empty string "" otherwise.
+ */
+ const std::string& getMiddlewareLibraryPath(const std::string& middlewareIdentifier) const;
+
+ /**
+ * Returns the paths to other generic libraries configured for a specific binding.
+ *
+ * This function is meant to be called by middleware libraries. Will return all configured paths to
+ * generic libraries. You likely wil want to use the utility functions provided in <CommonAPI/utils.h>
+ * to do the loading. To arrange and time the loading is responsibility of the middleware only.
+ *
+ * @return A vector containing all generic libraries associated with the given middlewareIdentifier.
+ */
+ const std::vector<std::string>& getGenericLibraryPaths(const std::string& middlewareIdentifier) const;
+
+ /**
+ * Returns the configured default middleware identifier.
+ *
+ * If no default has been configured, the empty string "" will be returned.
+ *
+ * @return The configured default middleware identifier.
+ */
+ const std::string& getDefaultMiddlewareIdentifier() const;
+
+ private:
+ Configuration() = default;
+
+ void readConfigFile(std::ifstream& addressConfigFile);
+ void retrieveCommonApiConfiguration();
+ void readEnvironmentVariables();
+};
+
+
+
+} // namespace CommonAPI
+
+#endif /* COMMONAPI_CONFIGURATION_H_ */
diff --git a/src/CommonAPI/Factory.h b/src/CommonAPI/Factory.h
index ede8536..91bafda 100644
--- a/src/CommonAPI/Factory.h
+++ b/src/CommonAPI/Factory.h
@@ -23,6 +23,7 @@
#include "Proxy.h"
#include "Stub.h"
#include "types.h"
+#include "utils.h"
namespace CommonAPI {
diff --git a/src/CommonAPI/Factory.hpp b/src/CommonAPI/Factory.hpp
index 2f481f5..6ba73f6 100644
--- a/src/CommonAPI/Factory.hpp
+++ b/src/CommonAPI/Factory.hpp
@@ -19,7 +19,10 @@ Factory::buildProxy(const std::string& participantId,
const std::string& domain) {
std::shared_ptr<Proxy> abstractMiddlewareProxy = createProxy(_ProxyClass<_AttributeExtensions...>::getInterfaceId(), participantId, serviceName, domain);
- return std::make_shared<_ProxyClass<_AttributeExtensions...>>(abstractMiddlewareProxy);
+ if (abstractMiddlewareProxy) {
+ return std::make_shared<_ProxyClass<_AttributeExtensions...>>(abstractMiddlewareProxy);
+ }
+ return NULL;
}
template<template<typename ...> class _ProxyClass, typename ... _AttributeExtensions >
@@ -43,7 +46,10 @@ Factory::buildProxyWithDefaultAttributeExtension(const std::string& participantI
const std::string& domain) {
std::shared_ptr<Proxy> abstractMiddlewareProxy = createProxy(DefaultAttributeProxyFactoryHelper<_ProxyClass, _AttributeExtension>::class_t::getInterfaceId(), participantId, serviceName, domain);
- return std::make_shared<typename DefaultAttributeProxyFactoryHelper<_ProxyClass, _AttributeExtension>::class_t>(abstractMiddlewareProxy);
+ if (abstractMiddlewareProxy) {
+ return std::make_shared<typename DefaultAttributeProxyFactoryHelper<_ProxyClass, _AttributeExtension>::class_t>(abstractMiddlewareProxy);
+ }
+ return NULL;
}
template <template<typename ...> class _ProxyClass, template<typename> class _AttributeExtension>
diff --git a/src/CommonAPI/MiddlewareInfo.h b/src/CommonAPI/MiddlewareInfo.h
index 6b69691..ffbc21c 100644
--- a/src/CommonAPI/MiddlewareInfo.h
+++ b/src/CommonAPI/MiddlewareInfo.h
@@ -23,31 +23,16 @@ namespace CommonAPI {
class Runtime;
-inline int FNV1aHash(const char* s) {
- const int FNV_offset_basis = 2166136261u;
- const int FNV_prime = 16777619;
-
- int hashValue = FNV_offset_basis;
- for (unsigned int i = 0; i < strlen(s); i++) {
- hashValue = (hashValue ^ s[i]) * FNV_prime;
- }
- return hashValue;
-}
-
-
typedef std::shared_ptr<Runtime> (*MiddlewareRuntimeLoadFunction) ();
struct MiddlewareInfo {
const char* middlewareName_;
- const int middlewareId_;
MiddlewareRuntimeLoadFunction getInstance_;
MiddlewareInfo(const char* middlewareName, MiddlewareRuntimeLoadFunction middlewareRuntimeLoadFunction):
middlewareName_(middlewareName),
- middlewareId_(FNV1aHash(middlewareName)),
- getInstance_(middlewareRuntimeLoadFunction) {
-}
+ getInstance_(middlewareRuntimeLoadFunction) {}
};
diff --git a/src/CommonAPI/Runtime.cpp b/src/CommonAPI/Runtime.cpp
index f5a8096..83ef63d 100644
--- a/src/CommonAPI/Runtime.cpp
+++ b/src/CommonAPI/Runtime.cpp
@@ -4,52 +4,350 @@
* 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 "Runtime.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <dlfcn.h>
+#include <algorithm>
#include <iostream>
+#include <unordered_map>
+#include <stdexcept>
+
+#include "Runtime.h"
+#include "Configuration.h"
+#include "utils.h"
namespace CommonAPI {
-std::unordered_map<std::string, MiddlewareRuntimeLoadFunction>* registeredRuntimeLoadFunctions_;
+static std::unordered_map<std::string, MiddlewareRuntimeLoadFunction>* registeredRuntimeLoadFunctions_;
+static bool isDynamic_ = false;
+static const char COMMONAPI_LIB_PREFIX[] = "libCommonAPI-";
+static const char MIDDLEWARE_INFO_SYMBOL_NAME[] = "middlewareInfo";
-void Runtime::registerRuntimeLoader(std::string middlewareName, MiddlewareRuntimeLoadFunction middlewareRuntimeLoadFunction) {
- if(!registeredRuntimeLoadFunctions_) {
+
+inline bool Runtime::tryLoadLibrary(const std::string& libraryPath, void** sharedLibraryHandle, MiddlewareInfo** foundMiddlewareInfo) {
+ //In case we find an already loaded library again while looking for another one,
+ //there is no need to look at it
+ if (dlopen(libraryPath.c_str(), RTLD_NOLOAD)) {
+ return false;
+ }
+ //In order to place symbols of the newly loaded library ahead of already resolved symbols, we need
+ //RTLD_DEEPBIND. This is necessary for this case: A library already is linked at compile time, but while
+ //trying to resolve another library dynamically we might find the very same library again.
+ //dlopen() doesn't know about the compile time linked library and will close it if dlclose() ever is
+ //called, thereby causing memory corruptions and the like. Therefore, we must be able to access the
+ //middlewareInfo of the newly dlopened library in order to determine whether it already has been linked.
+ *sharedLibraryHandle = dlopen(libraryPath.c_str(), RTLD_LAZY | RTLD_LOCAL | RTLD_DEEPBIND);
+ if (sharedLibraryHandle == NULL) {
+ return false;
+ }
+
+ *foundMiddlewareInfo = static_cast<MiddlewareInfo*>(dlsym(*sharedLibraryHandle, MIDDLEWARE_INFO_SYMBOL_NAME));
+
+ //In this context, a resolved value of NULL it is just as invalid as if dlerror() was set.
+ if (!*foundMiddlewareInfo) {
+ dlclose(*sharedLibraryHandle);
+ return false;
+ }
+
+ if (!(*foundMiddlewareInfo)->middlewareName_ || !(*foundMiddlewareInfo)->getInstance_) {
+ dlclose(sharedLibraryHandle);
+ return false;
+ }
+
+ return true;
+}
+
+
+bool Runtime::checkAndLoadLibrary(const std::string& libraryPath, const std::string& requestedBindingIdentifier, bool keepLibrary) {
+ void* sharedLibraryHandle = NULL;
+ MiddlewareInfo* foundMiddlewareInfo;
+ if (!tryLoadLibrary(libraryPath, &sharedLibraryHandle, &foundMiddlewareInfo)) {
+ return false;
+ }
+
+ if (foundMiddlewareInfo->middlewareName_ != requestedBindingIdentifier) {
+ //If library was linked at compile time (and therefore an appropriate runtime loader is registered),
+ //the library must not be closed!
+ auto foundRegisteredRuntimeLoader = registeredRuntimeLoadFunctions_->find(foundMiddlewareInfo->middlewareName_);
+ if (foundRegisteredRuntimeLoader == registeredRuntimeLoadFunctions_->end()) {
+ dlclose(sharedLibraryHandle);
+ }
+ return false;
+ }
+
+ if (!keepLibrary) {
+ dlclose(sharedLibraryHandle);
+ } else {
+ //Extend visibility to make symbols available to all other libraries loaded afterwards,
+ //e.g. libraries containing generated binding specific code.
+ sharedLibraryHandle = dlopen(libraryPath.c_str(), RTLD_NOW | RTLD_GLOBAL);
+ if (!sharedLibraryHandle) {
+ return false;
+ }
+ registeredRuntimeLoadFunctions_->insert( {foundMiddlewareInfo->middlewareName_, foundMiddlewareInfo->getInstance_} );
+ }
+
+ return true;
+}
+
+
+bool Runtime::checkAndLoadDefaultLibrary(std::string& foundBindingIdentifier, const std::string& libraryPath) {
+ void* sharedLibraryHandle = NULL;
+ MiddlewareInfo* foundMiddlewareInfo;
+ if (!tryLoadLibrary(libraryPath, &sharedLibraryHandle, &foundMiddlewareInfo)) {
+ return false;
+ }
+
+ //Extend visibility to make symbols available to all other linked libraries,
+ //e.g. libraries containing generated binding specific code
+ sharedLibraryHandle = dlopen(libraryPath.c_str(), RTLD_NOW | RTLD_GLOBAL);
+ if (!sharedLibraryHandle) {
+ return false;
+ }
+ registeredRuntimeLoadFunctions_->insert( {foundMiddlewareInfo->middlewareName_, foundMiddlewareInfo->getInstance_} );
+ foundBindingIdentifier = foundMiddlewareInfo->middlewareName_;
+
+ return true;
+}
+
+
+const std::vector<std::string> Runtime::readDirectory(const std::string& path) {
+ std::vector<std::string> result;
+ struct stat filestat;
+
+ DIR *directory = opendir(path.c_str());
+
+ if (!directory) {
+ return std::vector<std::string>();
+ }
+
+ struct dirent* entry;
+
+ while ((entry = readdir(directory))) {
+ const std::string fqnOfEntry = path + entry->d_name;
+
+ if (stat(fqnOfEntry.c_str(), &filestat)) {
+ continue;
+ }
+ if (S_ISDIR(filestat.st_mode)) {
+ continue;
+ }
+
+ if (strncmp(COMMONAPI_LIB_PREFIX, entry->d_name, strlen(COMMONAPI_LIB_PREFIX)) != 0) {
+ continue;
+ }
+
+ const char* fileNamePtr = entry->d_name;
+ while ((fileNamePtr = strchr(fileNamePtr + 1, '.'))) {
+ if (strncmp(".so", fileNamePtr, 3) == 0) {
+ break;
+ }
+ }
+
+ if (fileNamePtr) {
+ result.push_back(fqnOfEntry);
+ }
+ }
+
+ closedir (directory);
+
+ std::sort( result.begin(), result.end() );
+
+ return result;
+}
+
+
+struct LibraryVersion {
+ int32_t major;
+ int32_t minor;
+ int32_t revision;
+};
+
+bool operator<(LibraryVersion const& lhs, LibraryVersion const& rhs) {
+ if (lhs.major == rhs.major) {
+ if (lhs.minor == rhs.minor) {
+ return lhs.revision < rhs.revision;
+ }
+ return lhs.minor < rhs.minor;
+ }
+ return lhs.major < rhs.major;
+}
+
+
+std::shared_ptr<Runtime> Runtime::checkDynamicLibraries(const std::string& requestedMiddlewareName, LoadState& loadState) {
+ const std::string& middlewareLibraryPath = Configuration::getInstance().getMiddlewareLibraryPath(requestedMiddlewareName);
+
+ if (middlewareLibraryPath != "") {
+ if (!checkAndLoadLibrary(middlewareLibraryPath, requestedMiddlewareName, true)) {
+ //A path for requestedMiddlewareName was configured, but no corresponding library was found
+ loadState = LoadState::CONFIGURATION_ERROR;
+ return std::shared_ptr<Runtime>(NULL);
+ } else {
+ const std::string currentBinaryFQN = getCurrentBinaryFileFQN();
+ const uint32_t lastPathSeparatorPosition = currentBinaryFQN.find_last_of("/\\");
+ const std::string currentBinaryPath = currentBinaryFQN.substr(0, lastPathSeparatorPosition + 1);
+ auto foundRuntimeLoader = registeredRuntimeLoadFunctions_->find(requestedMiddlewareName);
+ if (foundRuntimeLoader != registeredRuntimeLoadFunctions_->end()) {
+ return (foundRuntimeLoader->second)();
+ }
+ //One should not get here
+ loadState = LoadState::BINDING_ERROR;
+ return std::shared_ptr<Runtime>(NULL);
+ }
+ }
+
+ const std::vector<std::string>& librarySearchPaths = Configuration::getInstance().getLibrarySearchPaths();
+
+ LibraryVersion highestVersionFound = {0, 0, 0};
+ std::string fqnOfHighestVersion = "";
+ struct stat filestat;
+
+ for (const std::string& singleSearchPath: librarySearchPaths) {
+ std::vector<std::string> orderedLibraries = readDirectory(singleSearchPath);
+
+ for (const std::string& fqnOfEntry : orderedLibraries) {
+ std::string versionString;
+ LibraryVersion currentLibraryVersion = {-1, -1, -1};
+
+
+ const char* fileNamePtr = fqnOfEntry.c_str();
+ while ((fileNamePtr = strchr(fileNamePtr + 1, '.'))) {
+ if (strncmp(".so", fileNamePtr, 3) == 0) {
+ break;
+ }
+ }
+
+ const char* positionOfFirstDot = strchr(fileNamePtr + 1, '.');
+ if (positionOfFirstDot) {
+ versionString = positionOfFirstDot + 1;
+ }
+
+ std::vector<std::string> versionElements = split(versionString, '.');
+ if (versionElements.size() >= 1 && containsOnlyDigits(versionElements[0])) {
+ currentLibraryVersion.major = strtol(versionElements[0].c_str(), NULL, 0);
+ }
+ if (versionElements.size() >= 3 && containsOnlyDigits(versionElements[2])) {
+ currentLibraryVersion.minor = strtol(versionElements[1].c_str(), NULL, 0);
+ currentLibraryVersion.revision = strtol(versionElements[2].c_str(), NULL, 0);
+ }
+
+ if (highestVersionFound < currentLibraryVersion) {
+ if (!checkAndLoadLibrary(fqnOfEntry, requestedMiddlewareName, false)) {
+ continue;
+ }
+ highestVersionFound = currentLibraryVersion;
+ fqnOfHighestVersion = fqnOfEntry;
+ }
+ }
+ }
+
+ if (fqnOfHighestVersion != "") {
+ checkAndLoadLibrary(fqnOfHighestVersion, requestedMiddlewareName, true);
+
+ auto foundRuntimeLoader = registeredRuntimeLoadFunctions_->find(requestedMiddlewareName);
+ if (foundRuntimeLoader != registeredRuntimeLoadFunctions_->end()) {
+ std::shared_ptr<Runtime> loadedRuntime = foundRuntimeLoader->second();
+ if (!loadedRuntime) {
+ loadState = LoadState::BINDING_ERROR;
+ }
+ return loadedRuntime;
+ }
+ }
+
+ loadState = LoadState::NO_LIBRARY_FOUND;
+
+ return std::shared_ptr<Runtime>();
+}
+
+
+std::shared_ptr<Runtime> Runtime::checkDynamicLibraries(LoadState& loadState) {
+ const std::string& defaultBindingIdentifier = Configuration::getInstance().getDefaultMiddlewareIdentifier();
+ if (defaultBindingIdentifier != "") {
+ return checkDynamicLibraries(defaultBindingIdentifier, loadState);
+ }
+
+ const std::vector<std::string>& librarySearchPaths = Configuration::getInstance().getLibrarySearchPaths();
+
+ for (const std::string& singleSearchPath : librarySearchPaths) {
+ std::vector<std::string> orderedLibraries = readDirectory(singleSearchPath);
+
+ for (const std::string& fqnOfEntry: orderedLibraries) {
+ std::string foundBindingName;
+ if (!checkAndLoadDefaultLibrary(foundBindingName, fqnOfEntry)) {
+ continue;
+ }
+
+ auto foundRuntimeLoader = registeredRuntimeLoadFunctions_->find(foundBindingName);
+ if (foundRuntimeLoader != registeredRuntimeLoadFunctions_->end()) {
+ return (foundRuntimeLoader->second)();
+ }
+ }
+ }
+
+ loadState = LoadState::NO_LIBRARY_FOUND;
+
+ return std::shared_ptr<Runtime>();
+}
+
+
+void Runtime::registerRuntimeLoader(const std::string& middlewareName, const MiddlewareRuntimeLoadFunction& middlewareRuntimeLoadFunction) {
+ if (!registeredRuntimeLoadFunctions_) {
registeredRuntimeLoadFunctions_ = new std::unordered_map<std::string, MiddlewareRuntimeLoadFunction>();
}
- registeredRuntimeLoadFunctions_->insert({middlewareName, middlewareRuntimeLoadFunction});
+ if (!isDynamic_) {
+ registeredRuntimeLoadFunctions_->insert( {middlewareName, middlewareRuntimeLoadFunction});
+ }
}
std::shared_ptr<Runtime> Runtime::load() {
+ LoadState dummyState;
+ return load(dummyState);
+}
+
+
+std::shared_ptr<Runtime> Runtime::load(LoadState& loadState) {
+ isDynamic_ = true;
+ loadState = LoadState::SUCCESS;
if(!registeredRuntimeLoadFunctions_) {
- registeredRuntimeLoadFunctions_ = new std::unordered_map<std::string, MiddlewareRuntimeLoadFunction> {};
+ registeredRuntimeLoadFunctions_ = new std::unordered_map<std::string, MiddlewareRuntimeLoadFunction>();
}
- auto begin = registeredRuntimeLoadFunctions_->begin();
+ const auto defaultRuntimeLoader = registeredRuntimeLoadFunctions_->begin();
- if (begin != registeredRuntimeLoadFunctions_->end()) {
- return (begin->second)();
+ if (defaultRuntimeLoader != registeredRuntimeLoadFunctions_->end()) {
+ return (defaultRuntimeLoader->second)();
}
- return std::shared_ptr<Runtime>(NULL);
+ return checkDynamicLibraries(loadState);
}
-std::shared_ptr<Runtime> Runtime::load(const std::string& middlewareName) {
- if(!registeredRuntimeLoadFunctions_) {
- registeredRuntimeLoadFunctions_ = new std::unordered_map<std::string, MiddlewareRuntimeLoadFunction> {};
+std::shared_ptr<Runtime> Runtime::load(const std::string& middlewareIdOrAlias) {
+ LoadState dummyState;
+ return load(middlewareIdOrAlias, dummyState);
+}
+
+std::shared_ptr<Runtime> Runtime::load(const std::string& middlewareIdOrAlias, LoadState& loadState) {
+ isDynamic_ = true;
+ loadState = LoadState::SUCCESS;
+ if (!registeredRuntimeLoadFunctions_) {
+ registeredRuntimeLoadFunctions_ = new std::unordered_map<std::string, MiddlewareRuntimeLoadFunction>();
}
- for (auto it = registeredRuntimeLoadFunctions_->begin(); it != registeredRuntimeLoadFunctions_->end(); ++it) {
- if(it->first == middlewareName) {
- return (it->second)();
- }
+ const std::string middlewareName = Configuration::getInstance().getMiddlewareNameForAlias(middlewareIdOrAlias);
+
+ auto foundRuntimeLoader = registeredRuntimeLoadFunctions_->find(middlewareName);
+ if (foundRuntimeLoader != registeredRuntimeLoadFunctions_->end()) {
+ return (foundRuntimeLoader->second)();
}
- return std::shared_ptr<Runtime>(NULL);
+ return checkDynamicLibraries(middlewareName, loadState);
}
diff --git a/src/CommonAPI/Runtime.h b/src/CommonAPI/Runtime.h
index c0040a8..0a93ccc 100644
--- a/src/CommonAPI/Runtime.h
+++ b/src/CommonAPI/Runtime.h
@@ -17,12 +17,11 @@
#include "MainLoopContext.h"
#include <memory>
-#include <fstream>
#include <unordered_map>
-#include <dlfcn.h>
#include <string>
#include <cassert>
#include <cstring>
+#include <mutex>
namespace CommonAPI {
@@ -40,41 +39,90 @@ class ServicePublisher;
*/
class Runtime {
public:
+ enum class LoadState {
+ SUCCESS,
+ NO_LIBRARY_FOUND,
+ CONFIGURATION_ERROR,
+ BINDING_ERROR
+ };
+
+ virtual ~Runtime() {}
+
/**
* \brief Loads the default runtime.
*
- * Loads the runtime for the default middleware binding. This either is the only binding available,
- * or the one defined as default in the configuration.
+ * Loads the runtime for the default middleware binding. This can be
+ * * One of the middleware bindings that were linked at compile time
+ * * The first middleware binding that is encountered when resolving bindings at runtime
+ * * The middleware binding that was configured as default in the corresponding configuration
+ * file (throws an error if no such binding exists)
*
- * @return The runtime object for the default binding
+ * @return The runtime object for the default binding, or null if any error occurred
*/
static std::shared_ptr<Runtime> load();
/**
+ * \brief Loads the default runtime and notifies the caller of any errors.
+ *
+ * Loads the runtime for the default middleware binding. This can be
+ * * One of the middleware bindings that were linked at compile time
+ * * The first middleware binding that is encountered when resolving bindings at runtime
+ * * The middleware binding that was configured as default in the corresponding configuration
+ * file (throws an error if no such binding exists)
+ *
+ * @param loadState: An enumeration that will be set appropriately after loading has finished or
+ * aborted. May be used for debugging purposes.
+ *
+ * @return The runtime object for the default binding, or null if any error occurred. In the latter
+ * case, loadState will be set to an appropriate value.
+ */
+ static std::shared_ptr<Runtime> load(LoadState& loadState);
+
+ /**
* \brief Loads specified runtime.
*
- * Loads the runtime for the specified middleware binding. The given middleware ID can be either
+ * Loads the runtime for the specified middleware binding. The given well known name can be either
* the well known name defined by a binding, or a configured alias for a binding.
*
- * @return The runtime object for specified binding
+ * @param middlewareIdOrAlias A well known name or an alias for a binding
+ *
+ * @return The runtime object for specified binding, or null if any error occurred.
+ *
+ * @throw std::invalid_argument if a path for this middlewareId has been configured, but no appropriate library
+ * could be found there.
*/
- static std::shared_ptr<Runtime> load(const std::string& middlewareId);
+ static std::shared_ptr<Runtime> load(const std::string& middlewareIdOrAlias);
+
+ /**
+ * \brief Loads specified runtime.
+ *
+ * Loads the runtime for the specified middleware binding. The given well known name can be either
+ * the well known name defined by a binding, or a configured alias for a binding.
+ *
+ * @param middlewareIdOrAlias A well known name or an alias for a binding.
+ * @param loadState: An enumeration that will be set appropriately after loading has finished or
+ * aborted. May be used for debugging purposes.
+ *
+ * @return The runtime object for specified binding, or null if any error occurred. In the latter
+ * case, loadState will be set to an appropriate value.
+ */
+ static std::shared_ptr<Runtime> load(const std::string& middlewareIdOrAlias, LoadState& loadState);
/**
* \brief Called by bindings to register their runtime loaders. Do not call from applications.
*
* Called by bindings to register their runtime loaders. Do not call from applications.
*/
- static void registerRuntimeLoader(std::string middlewareName, MiddlewareRuntimeLoadFunction middlewareRuntimeLoadFunction);
-
- virtual ~Runtime() {}
+ static void registerRuntimeLoader(const std::string& middlewareName, const MiddlewareRuntimeLoadFunction& middlewareRuntimeLoadFunction);
/**
- * \brief Returns new MainLoopContext
+ * \brief Returns new MainLoopContext.
*
* Creates and returns a new MainLoopContext object. This context can be used to take
* complete control over the order and time of execution of the abstract middleware
- * dispatching mechanism.
+ * dispatching mechanism. Make sure to register all callback functions before subsequently
+ * handing it to createFactory(), as during creation of the factory object the callbacks may
+ * already be called.
*
* @return A new MainLoopContext object
*/
@@ -100,9 +148,9 @@ class Runtime {
*
* @return Factory object for this runtime
*/
- virtual std::shared_ptr<Factory> createFactory(std::shared_ptr<MainLoopContext> mainLoopContext = std::shared_ptr<MainLoopContext>(NULL),
- const std::string factoryName = "",
- const bool nullOnInvalidName = false);
+ std::shared_ptr<Factory> createFactory(std::shared_ptr<MainLoopContext> mainLoopContext = std::shared_ptr<MainLoopContext>(NULL),
+ const std::string factoryName = "",
+ const bool nullOnInvalidName = false);
/**
* \brief Create a factory for the loaded runtime.
@@ -119,8 +167,8 @@ class Runtime {
*
* @return Factory object for this runtime
*/
- virtual std::shared_ptr<Factory> createFactory(const std::string factoryNamey,
- const bool nullOnInvalidName = false);
+ std::shared_ptr<Factory> createFactory(const std::string factoryNamey,
+ const bool nullOnInvalidName = false);
/**
* \brief Returns the ServicePublisher object for this runtime.
@@ -136,8 +184,20 @@ class Runtime {
protected:
virtual std::shared_ptr<Factory> doCreateFactory(std::shared_ptr<MainLoopContext> mainLoopContext,
- const std::string factoryName,
+ const std::string& factoryName,
const bool nullOnInvalidName = false) = 0;
+
+ private:
+ static const std::vector<std::string> readDirectory(const std::string& path);
+
+ static std::shared_ptr<Runtime> checkDynamicLibraries(LoadState& loadState);
+ static std::shared_ptr<Runtime> checkDynamicLibraries(const std::string& middlewareName, LoadState& loadState);
+
+ static bool tryLoadLibrary(const std::string& libraryPath, void** sharedLibraryHandle, MiddlewareInfo** foundMiddlewareInfo);
+ static bool checkAndLoadLibrary(const std::string& libraryPath, const std::string& requestedMiddlewareName, bool keepLibrary);
+ static bool checkAndLoadDefaultLibrary(std::string& foundBindingName, const std::string& libraryPath);
+
+ static void closeHandle(void* libraryHandle);
};
diff --git a/src/CommonAPI/utils.h b/src/CommonAPI/utils.h
new file mode 100644
index 0000000..c1c1c54
--- /dev/null
+++ b/src/CommonAPI/utils.h
@@ -0,0 +1,340 @@
+/* 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/. */
+#ifndef COMMONAPI_UTILS_H_
+#define COMMONAPI_UTILS_H_
+
+#include <unistd.h>
+#include <dirent.h>
+#include <dlfcn.h>
+#include <sys/stat.h>
+
+#include <cstring>
+#include <string>
+#include <sstream>
+#include <vector>
+#include <algorithm>
+#include <iostream>
+
+
+namespace CommonAPI {
+
+
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
+# define COMMONAPI_DEPRECATED __attribute__ ((__deprecated__))
+#elif defined(_MSC_VER) && (_MSC_VER >= 1300)
+# define COMMONAPI_DEPRECATED __declspec(deprecated)
+#else
+# define COMMONAPI_DEPRECATED
+#endif
+
+
+/**
+ * \brief Returns the fully qualified name of the binary.
+ *
+ * @return The name of the currently executing binary.
+ */
+inline std::string getCurrentBinaryFileFQN() {
+ char fqnOfBinary[FILENAME_MAX];
+ char pathToProcessImage[FILENAME_MAX];
+
+ sprintf(pathToProcessImage, "/proc/%d/exe", getpid());
+ const ssize_t lengthOfFqn = readlink(pathToProcessImage, fqnOfBinary, sizeof(fqnOfBinary) - 1);
+
+ if (lengthOfFqn != -1) {
+ fqnOfBinary[lengthOfFqn] = '\0';
+ return std::string(std::move(fqnOfBinary));
+ } else {
+ return std::string("");
+ }
+}
+
+/**
+ * \brief Splits a std::string according to the given delim-char.
+ *
+ * The string will be splitted at each position the delim char is encountered. The delim itself
+ * will be removed from the result.
+ *
+ * @param s: The string that is to be splitted
+ * @param delim: The character that separates the resulting string tokens in the original string
+ * @param elems: Reference to the vector that shall be filled with the splitted string elements.
+ *
+ * @return A reference to the vector you passed in (elems)
+ */
+inline std::vector<std::string>& split(const std::string& s, char delim, std::vector<std::string>& elems) {
+ std::istringstream ss(s);
+ std::string item;
+ while (std::getline(ss, item, delim)) {
+ elems.push_back(item);
+ }
+ return elems;
+}
+
+/**
+ * \brief Splits a std::string according to the given delim-char.
+ *
+ * The string will be splitted at each position the delim char is encountered. The delim itself
+ * will be removed from the result.
+ *
+ * @param s: The string that is to be splitted
+ * @param delim: The character that separates the resulting string tokens in the original string
+ *
+ * @return A vector containing the splitted string elements.
+ */
+inline std::vector<std::string> split(const std::string& s, char delim) {
+ std::vector<std::string> elems;
+ return split(s, delim, elems);
+}
+
+/**
+ * \brief Trims whitespaces from beginning and end of a std::string.
+ *
+ * @param toTrim: The string that is to be trimmed.
+ */
+inline void trim(std::string& toTrim) {
+ toTrim.erase(
+ toTrim.begin(),
+ std::find_if(toTrim.begin(),
+ toTrim.end(),
+ std::not1(std::ptr_fun<int, int>(std::isspace)))
+ );
+ toTrim.erase(
+ std::find_if(toTrim.rbegin(),
+ toTrim.rend(),
+ std::not1(std::ptr_fun<int, int>(std::isspace))).base(),
+ toTrim.end()
+ );
+}
+
+/**
+ * \brief Checks whether the given string contains nothing but digits.
+ *
+ * @param toCheck: The string that is to be checked on the presence of anything but digits.
+ *
+ * @return true if toCheck contains nothing but digits, false otherwise.
+ */
+inline bool containsOnlyDigits(const std::string& toCheck) {
+ auto firstNonDigitIt = std::find_if(
+ toCheck.begin(),
+ toCheck.end(),
+ [](char c) {
+ return !std::isdigit(c);
+ });
+
+ return firstNonDigitIt == toCheck.end();
+}
+
+/**
+ * \brief Checks whether the given string contains nothing but alphanumeric characters.
+ *
+ * @param toCheck: The string that is to be checked on the presence of anything but alphanumeric characters.
+ *
+ * @return true if toCheck contains nothing but alphanumeric characters, false otherwise.
+ */
+inline bool containsOnlyAlphanumericCharacters(const std::string& toCheck) {
+ auto firstNonAlphanumericCharacterIt = std::find_if(
+ toCheck.begin(),
+ toCheck.end(),
+ [](char c) {
+ return !std::isalnum(c);
+ });
+
+ return firstNonAlphanumericCharacterIt == toCheck.end();
+}
+
+/**
+ * \brief Checks whether the given std::string is a valid CommonAPI domain name.
+ *
+ * @param domainName: The std::string that is to be checked.
+ *
+ * @return true if domainName is a valid CommonAPI domainName, false otherwise.
+ */
+inline bool isValidDomainName(const std::string& domainName) {
+ return containsOnlyAlphanumericCharacters(domainName);
+}
+
+/**
+ * \brief Checks whether the given std::string is a valid CommonAPI service name.
+ *
+ * @param serviceName: The std::string that is to be checked.
+ *
+ * @return true if serviceName is a valid CommonAPI serviceName, false otherwise.
+ */
+inline bool isValidServiceName(const std::string& serviceName) {
+ bool isValid = serviceName[0] != '.' && serviceName[serviceName.size() - 1] != '.';
+
+ if (isValid) {
+ std::vector<std::string> splittedServiceName = split(serviceName, '.');
+
+ for (auto serviceNameElementIt = splittedServiceName.begin();
+ serviceNameElementIt != splittedServiceName.end() && isValid;
+ ++serviceNameElementIt) {
+ isValid &= containsOnlyAlphanumericCharacters(*serviceNameElementIt);
+ }
+ }
+
+ return isValid;
+}
+
+/**
+ * \brief Checks whether the given std::string is a valid CommonAPI instance ID.
+ *
+ * @param instanceId: The std::string that is to be checked.
+ *
+ * @return true if instanceId is a valid CommonAPI instance ID, false otherwise.
+ */
+inline bool isValidInstanceId(const std::string& instanceId) {
+ //Validation rules for ServiceName and InstanceID are equivalent
+ return isValidServiceName(instanceId);
+}
+
+/**
+ * \brief Checks whether the given std::string is a valid CommonAPI address.
+ *
+ * @param commonApiAddressName: The std::string that is to be checked.
+ *
+ * @return true if commonApiAddress is a valid CommonAPI address, false otherwise.
+ */
+inline bool isValidCommonApiAddress(const std::string& commonApiAddress) {
+ std::vector<std::string> splittedAddress = split(commonApiAddress, ':');
+ if (splittedAddress.size() != 3) {
+ return false;
+ }
+ return isValidDomainName(splittedAddress[0]) && isValidServiceName(splittedAddress[1]) && isValidInstanceId(splittedAddress[2]);
+}
+
+
+/**
+ * \brief Loads a specific generic library at runtime.
+ *
+ * The library will be loaded using dlopen(3) with the flags (RTLD_NOW | RTLD_GLOBAL), if all pre-checks are
+ * successful. Pre-checks include the verification that the given parameters actually point to a library and
+ * optionally if the library matches the standard name pattern for CommonAPI generic libraries. The standard
+ * name pattern is "lib<wellKnownMiddlewareName>Gen-<arbitraryName>.so[.major[.minor.revision]]".
+ *
+ * @param wellKnownMiddlewareName: The name of the middleware that requests the loading of the library.
+ * @param libraryName: The name of the library that shall be loaded.
+ * @param path: The path at which the library is to be found. path + library name together make up the fully
+ * qualified name of the library.
+ * @param checkStandardNamePattern: If set to true, it will be ensured the library matches the CommonAPI
+ * standard name pattern for generic libraries. This is meant as a safety measure
+ * to prevent the loading of unnecessary or the wrong libraries. Set to false if
+ * you are sure about what you are doing.
+ * @return true if the library could be loaded successfully, false otherwise.
+ *
+ * @note The well known middleware name is included as a parameter because the additional libraries normally are needed
+ * only by specific middlewares. This name however will only be taken into consideration during name checking
+ * if the checkStandardNamePattern flag is set to true.
+ */
+inline bool loadGenericLibrary(const std::string& wellKnownMiddlewareName, const std::string& libraryName, const std::string& path, bool checkStandardNamePattern = true) {
+ std::string fqnOfLibrary = path + libraryName;
+ struct stat filestat;
+ if (stat(fqnOfLibrary.c_str(), &filestat)) {
+ return false;
+ }
+ if (S_ISDIR(filestat.st_mode)) {
+ return false;
+ }
+
+ if (checkStandardNamePattern) {
+ const std::string generatedLibPrefix = "lib" + wellKnownMiddlewareName + "Gen-";
+ if (strncmp(generatedLibPrefix.c_str(), libraryName.c_str(), generatedLibPrefix.length()) != 0) {
+ return false;
+ }
+
+ const char* fileNamePtr = libraryName.c_str();
+ while ((fileNamePtr = strchr(fileNamePtr + 1, '.'))) {
+ if (strncmp(".so", fileNamePtr, 3) == 0) {
+ break;
+ }
+ }
+
+ if (!fileNamePtr) {
+ return false;
+ }
+ }
+
+ dlopen(fqnOfLibrary.c_str(), RTLD_NOW | RTLD_GLOBAL);
+ return true;
+}
+
+/**
+ * \brief Loads a specific generic library at runtime.
+ *
+ * The library will be loaded using dlopen(3) with the flags (RTLD_NOW | RTLD_GLOBAL), if all pre-checks are
+ * successful. Pre-checks include the verification that the given parameters actually point to a library and
+ * optionally if the library matches the standard name pattern for CommonAPI generic libraries. The standard
+ * name pattern is "lib<wellKnownMiddlewareName>Gen-<arbitraryName>.so[.major[.minor.revision]]".
+ *
+ * @param wellKnownMiddlewareName: The name of the middleware that requests the loading of the library.
+ * @param fqnOfLibrary: The fully qualified name of the library.
+ * @param checkStandardNamePattern: If set to true, it will be ensured the library matches the CommonAPI
+ * standard name pattern for generic libraries. This is meant as a safety measure
+ * to prevent the loading of unnecessary or the wrong libraries. Set to false if
+ * you are sure about what you are doing.
+ * @return true if the library could be loaded successfully, false otherwise.
+ *
+ * @note The well known middleware name is included as a parameter because the additional libraries normally are needed
+ * only by specific middlewares. This name however will only be taken into consideration during name checking
+ * if the checkStandardNamePattern flag is set to true.
+ */
+inline bool loadGenericLibrary(const std::string& wellKnownMiddlewareName,
+ const std::string& fqnOfLibrary,
+ bool checkStandardNamePattern = true) {
+ uint32_t position = fqnOfLibrary.find_last_of("/\\");
+ std::string path = fqnOfLibrary.substr(0, position + 1);
+ std::string file = fqnOfLibrary.substr(position + 1);
+ return loadGenericLibrary(wellKnownMiddlewareName, file, path, checkStandardNamePattern);
+}
+
+
+/**
+ * \brief Searches the given path for additional generic CommonAPI libraries and loads them.
+ *
+ * All libraries for which the pre-checks are successful will be loaded using dlopen(3) with the flags
+ * (RTLD_NOW | RTLD_GLOBAL). Pre-checks include the verification that the given parameters actually point
+ * to a library and if the library matches the standard name pattern for CommonAPI generic libraries.
+ * The standard name pattern is "lib<wellKnownMiddlewareName>Gen-<arbitraryName>.so[.major[.minor.revision]]".
+ *
+ * @param wellKnownMiddlewareName: The name of the middleware that requests the loading of the library. Will
+ * be used to perform the name check.
+ * @param singleSearchPath: The directory that is to be searched for libraries.
+ */
+inline void findAndLoadGenericLibraries(const std::string& requestedMiddlewareName, const std::string& singleSearchPath) {
+ DIR *directory = opendir(singleSearchPath.c_str());
+
+ if (directory != NULL) {
+ struct dirent* entry;
+
+ while ((entry = readdir(directory))) {
+ loadGenericLibrary(requestedMiddlewareName, entry->d_name, singleSearchPath, true);
+ }
+ }
+}
+
+/**
+ * \brief Searches the given paths for additional generic CommonAPI libraries and loads them.
+ *
+ * All libraries for which the pre-checks are successful will be loaded using dlopen(3) with the flags
+ * (RTLD_NOW | RTLD_GLOBAL). Pre-checks include the verification that the given parameters actually point
+ * to a library and if the library matches the standard name pattern for CommonAPI generic libraries.
+ * The standard name pattern is "lib<wellKnownMiddlewareName>Gen-<arbitraryName>.so[.major[.minor.revision]]".
+ *
+ * @param wellKnownMiddlewareName: The name of the middleware that requests the loading of the library. Will
+ * be used to perform the name check.
+ * @param searchPaths: The directories that are to be searched for libraries.
+ */
+inline void findAndLoadGenericLibraries(const std::string& requestedMiddlewareName, const std::vector<std::string>& searchPaths) {
+ for (const std::string& singleSearchPath : searchPaths) {
+ findAndLoadGenericLibraries(requestedMiddlewareName, singleSearchPath.c_str());
+ }
+}
+
+
+} //namespace CommonAPI
+
+
+#endif /* COMMONAPI_UTILS_H_ */