You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celix.apache.org by pn...@apache.org on 2022/10/31 22:02:26 UTC
[celix] 01/01: Refactor Celix utils and framework C++ headers for C++14 support
This is an automated email from the ASF dual-hosted git repository.
pnoltes pushed a commit to branch feature/cxx14_framework_support
in repository https://gitbox.apache.org/repos/asf/celix.git
commit 82cc3ffcd5ba7f5cf17a33c9211cdd7690c79881
Author: Pepijn Noltes <pe...@gmail.com>
AuthorDate: Mon Oct 31 23:01:50 2022 +0100
Refactor Celix utils and framework C++ headers for C++14 support
---
.github/workflows/macos-nightly.yml | 3 +
.github/workflows/macos.yml | 2 +
.github/workflows/ubuntu-nightly.yml | 4 +
.github/workflows/ubuntu.yml | 2 +
CMakeLists.txt | 2 +
README.md | 4 +-
libs/framework/gtest/CMakeLists.txt | 92 ++++++---
.../gtest/src/CxxBundleContextTestSuite.cc | 3 +-
libs/framework/include/celix/Bundle.h | 32 +++-
libs/framework/include/celix/BundleActivator.h | 8 +-
libs/framework/include/celix/BundleContext.h | 143 ++++++++++++--
libs/framework/include/celix/ServiceRegistration.h | 128 ++++++++-----
.../include/celix/ServiceRegistrationBuilder.h | 15 +-
libs/framework/include/celix/TrackerBuilders.h | 13 +-
libs/framework/include/celix/Trackers.h | 210 ++++++++++++++-------
libs/framework/include/celix/UseServiceBuilder.h | 11 +-
libs/utils/gtest/CMakeLists.txt | 29 +--
libs/utils/gtest/src/CxxUtilsTestSuite.cc | 18 +-
libs/utils/include/celix/Filter.h | 44 ++++-
libs/utils/include/celix/Properties.h | 21 ++-
libs/utils/include/celix/Utils.h | 40 ++--
21 files changed, 590 insertions(+), 234 deletions(-)
diff --git a/.github/workflows/macos-nightly.yml b/.github/workflows/macos-nightly.yml
index 8fdd6b98..6ca4191e 100644
--- a/.github/workflows/macos-nightly.yml
+++ b/.github/workflows/macos-nightly.yml
@@ -27,6 +27,9 @@ jobs:
BUILD_OPTIONS: |
-DENABLE_TESTING=ON
-DENABLE_ADDRESS_SANITIZER=ON
+ -DBUILD_CXX_REMOTE_SERVICE_ADMIN=ON
+ -DCELIX_TEST_DEPENDENCY_MANAGER_FOR_CXX11=ON
+ -DCELIX_TEST_FOR_CXX14=ON
run: |
mkdir build install
cd build
diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml
index 0517e80a..b14634ee 100644
--- a/.github/workflows/macos.yml
+++ b/.github/workflows/macos.yml
@@ -26,6 +26,8 @@ jobs:
-DENABLE_TESTING=ON
-DENABLE_ADDRESS_SANITIZER=ON
-DBUILD_CXX_REMOTE_SERVICE_ADMIN=ON
+ -DCELIX_TEST_DEPENDENCY_MANAGER_FOR_CXX11=ON
+ -DCELIX_TEST_FOR_CXX14=ON
run: |
mkdir build install
cd build
diff --git a/.github/workflows/ubuntu-nightly.yml b/.github/workflows/ubuntu-nightly.yml
index 6ce46e73..8a66c85d 100644
--- a/.github/workflows/ubuntu-nightly.yml
+++ b/.github/workflows/ubuntu-nightly.yml
@@ -56,6 +56,10 @@ jobs:
CXX: ${{ matrix.cxx_compiler }}
BUILD_OPTIONS: |
-DENABLE_TESTING=ON
+ -DBUILD_EXPERIMENTAL=ON
+ -DBUILD_CXX_REMOTE_SERVICE_ADMIN=ON
+ -DCELIX_TEST_DEPENDENCY_MANAGER_FOR_CXX11=ON
+ -DCELIX_TEST_FOR_CXX14=ON
BUILD_OPTIONS_SANITIZER: |
-DENABLE_ADDRESS_SANITIZER=ON
BUILD_OPTIONS_V3_API: |
diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml
index b95e44e4..7b78569f 100644
--- a/.github/workflows/ubuntu.yml
+++ b/.github/workflows/ubuntu.yml
@@ -56,6 +56,8 @@ jobs:
-DENABLE_TESTING=ON
-DBUILD_EXPERIMENTAL=ON
-DBUILD_CXX_REMOTE_SERVICE_ADMIN=ON
+ -DCELIX_TEST_DEPENDENCY_MANAGER_FOR_CXX11=ON
+ -DCELIX_TEST_FOR_CXX14=ON
BUILD_OPTIONS_SANITIZER: |
-DENABLE_ADDRESS_SANITIZER=ON
BUILD_OPTIONS_V3_API: |
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 42b3097f..575c43e1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -187,6 +187,8 @@ endif ()
option(CELIX_USE_ZIP_INSTEAD_OF_JAR "Default Celix cmake command will use jar to package bundle (if found). This option enforces Celix to use zip instead." OFF)
option(CELIX_CXX "Build C++ libraries and bundles. Note for tests C++ is always used." ON)
+option(CELIX_TEST_DEPENDENCY_MANAGER_FOR_CXX11 "Test the Dependency Manager for C++11 support" OFF)
+option(CELIX_TEST_FOR_CXX14 "Test celix utils and framework C++ header for C++14 support" OFF)
#Libraries and Launcher
add_subdirectory(libs)
diff --git a/README.md b/README.md
index 46e42d15..5024b23b 100644
--- a/README.md
+++ b/README.md
@@ -22,8 +22,8 @@ limitations under the License.
[![codecov](https://codecov.io/gh/apache/celix/branch/master/graph/badge.svg)](https://codecov.io/gh/apache/celix)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/6685/badge.svg)](https://scan.coverity.com/projects/6685)
-Apache Celix is an implementation of a dynamic service framework inspired by the OSGi specification and adapted to C
-and C++ (C++17).
+Apache Celix is an implementation of a dynamic service framework inspired by the OSGi specification and adapted to C,
+C++14 and C++17.
It is a framework to develop dynamic modular software applications using component and in-process service-oriented
programming.
diff --git a/libs/framework/gtest/CMakeLists.txt b/libs/framework/gtest/CMakeLists.txt
index 9de0023a..977fcf99 100644
--- a/libs/framework/gtest/CMakeLists.txt
+++ b/libs/framework/gtest/CMakeLists.txt
@@ -38,16 +38,19 @@ if(NOT APPLE)
endif()
add_dependencies(unresolvable_bundle sublib)
-add_executable(test_framework
- src/single_framework_test.cpp
- src/multiple_frameworks_test.cpp
- src/bundle_context_bundles_tests.cpp
- src/bundle_context_services_test.cpp
- src/DependencyManagerTestSuite.cc
- src/CxxBundleContextTestSuite.cc
- src/HelloWorldCxxActivator.cc
- src/CxxFrameworkFactoryTestSuite.cc
- src/CxxBundleActivatorTestSuite.cc)
+set(CELIX_FRAMEWORK_TEST_SOURCES
+ src/single_framework_test.cpp
+ src/multiple_frameworks_test.cpp
+ src/bundle_context_bundles_tests.cpp
+ src/bundle_context_services_test.cpp
+ src/DependencyManagerTestSuite.cc
+ src/CxxBundleContextTestSuite.cc
+ src/HelloWorldCxxActivator.cc
+ src/CxxFrameworkFactoryTestSuite.cc
+ src/CxxBundleActivatorTestSuite.cc
+)
+
+add_executable(test_framework ${CELIX_FRAMEWORK_TEST_SOURCES})
target_link_libraries(test_framework PRIVATE Celix::framework CURL::libcurl GTest::gtest GTest::gtest_main)
add_celix_bundle_dependencies(test_framework
simple_test_bundle1
@@ -93,21 +96,60 @@ target_compile_definitions(test_framework PRIVATE
add_test(NAME test_framework COMMAND test_framework)
setup_target_for_coverage(test_framework SCAN_DIR ..)
-#Setting standard to C++11 and testing C++ dependency manager to ensure that this still support C++11.
-#This ensure that the C++11 dependency manager is backwards compatible with Celix 2.2.1
-set(CMAKE_CXX_STANDARD 11)
-add_executable(test_dep_man_with_cxx11
- src/DependencyManagerTestSuite.cc
-)
-target_link_libraries(test_dep_man_with_cxx11 PRIVATE Celix::framework CURL::libcurl GTest::gtest GTest::gtest_main)
-target_compile_definitions(test_dep_man_with_cxx11 PRIVATE
- SIMPLE_CXX_DEP_MAN_BUNDLE_LOC="${SIMPLE_CXX_DEP_MAN_BUNDLE_LOC}"
-)
-add_test(NAME test_dep_man_with_cxx11 COMMAND test_dep_man_with_cxx11)
-setup_target_for_coverage(test_dep_man_with_cxx11 SCAN_DIR ..)
+if (CELIX_TEST_DEPENDENCY_MANAGER_FOR_CXX11)
+ #Setting standard to C++11 and testing C++ dependency manager to ensure that this still support C++11.
+ #This ensure that the C++11 dependency manager is backwards compatible with Celix 2.2.1
+ set(CMAKE_CXX_STANDARD 11)
+ add_executable(test_dep_man_with_cxx11
+ src/DependencyManagerTestSuite.cc
+ )
+ target_link_libraries(test_dep_man_with_cxx11 PRIVATE Celix::framework CURL::libcurl GTest::gtest GTest::gtest_main)
+ target_compile_definitions(test_dep_man_with_cxx11 PRIVATE
+ SIMPLE_CXX_DEP_MAN_BUNDLE_LOC="${SIMPLE_CXX_DEP_MAN_BUNDLE_LOC}"
+ )
+ add_test(NAME test_dep_man_with_cxx11 COMMAND test_dep_man_with_cxx11)
+ setup_target_for_coverage(test_dep_man_with_cxx11 SCAN_DIR ..)
+
+ #Also to ensure that CELIX_GEN_CXX_BUNDLE_ACTIVATOR still works for C++11 bundle activators with a
+ #dependency manager argument, the HelloWorldCxxActivatorWithDepMan will be used to create a C++11 bundle
+ add_celix_bundle(test_dep_man_bundle_activator_with_cxx11 SOURCES src/HelloWorldCxxActivatorWithDepMan.cc VERSION 1.0.0)
+endif ()
+
+if (CELIX_TEST_FOR_CXX14)
+ #Setting standard to C++14 and testing the C++ framework headers to ensure that C++14 is also supported.
+ set(CMAKE_CXX_STANDARD 14)
+
+ add_executable(test_framework_with_cxx14 ${CELIX_FRAMEWORK_TEST_SOURCES})
+ target_link_libraries(test_framework_with_cxx14 PRIVATE Celix::framework CURL::libcurl GTest::gtest GTest::gtest_main)
+ add_celix_bundle_dependencies(test_framework_with_cxx14
+ simple_test_bundle1
+ simple_test_bundle2 simple_test_bundle3 simple_test_bundle4
+ simple_test_bundle5 bundle_with_exception unresolveable_bundle simple_cxx_bundle simple_cxx_dep_man_bundle cmp_test_bundle)
+ target_include_directories(test_framework_with_cxx14 PRIVATE ../src)
+
+ #Also to ensure that CELIX_GEN_CXX_BUNDLE_ACTIVATOR still for C++11.
+ add_celix_bundle(simple_cxx_bundle_with_cxx1 SOURCES src/HelloWorldCxxActivator.cc VERSION 1.0.0)
+ add_celix_bundle(simple_cxx_dep_man_bundle_with_cxx1 SOURCES src/HelloWorldCxxActivatorWithDepMan.cc VERSION 1.0.0)
+ add_celix_bundle_dependencies(test_framework_with_cxx14 simple_cxx_bundle_with_cxx1 simple_cxx_dep_man_bundle_with_cxx1)
-#Also to ensure that CELIX_GEN_CXX_BUNDLE_ACTIVATOR still works for C++11 bundle activators with a
-#dependency manager argument, the HelloWorldCxxActivatorWithDepMan will be used to create a C++11 bundle
+ celix_get_bundle_file(simple_cxx_bundle_with_cxx1 SIMPLE_CXX_BUNDLE_WITH_CXX11_LOC)
+ celix_get_bundle_file(simple_cxx_dep_man_bundle_with_cxx1 SIMPLE_CXX_DEP_MAN_WITH_CXX11_BUNDLE_LOC)
-add_celix_bundle(test_dep_man_bundle_activator_with_cxx11 SOURCES src/HelloWorldCxxActivatorWithDepMan.cc VERSION 1.0.0)
+ target_compile_definitions(test_framework_with_cxx14 PRIVATE
+ SIMPLE_TEST_BUNDLE1_LOCATION="${SIMPLE_TEST_BUNDLE1}"
+ SIMPLE_TEST_BUNDLE2_LOCATION="${SIMPLE_TEST_BUNDLE2}"
+ SIMPLE_TEST_BUNDLE3_LOCATION="${SIMPLE_TEST_BUNDLE3}"
+ SIMPLE_TEST_BUNDLE4_LOCATION="${SIMPLE_TEST_BUNDLE4_FILENAME}"
+ SIMPLE_TEST_BUNDLE5_LOCATION="${SIMPLE_TEST_BUNDLE5_FILENAME}"
+ TEST_BUNDLE_WITH_EXCEPTION_LOCATION="${BUNDLE_WITH_EXCEPTION}"
+ TEST_BUNDLE_UNRESOLVABLE_LOCATION="${UNRESOLVABLE_BUNDLE}"
+ SIMPLE_CXX_BUNDLE_LOC="${SIMPLE_CXX_BUNDLE_WITH_CXX11_LOC}"
+ CMP_TEST_BUNDLE_LOC="${CMP_TEST_BUNDLE_LOC}"
+ SIMPLE_CXX_DEP_MAN_BUNDLE_LOC="${SIMPLE_CXX_DEP_MAN_WITH_CXX11_BUNDLE_LOC}"
+ CMP_TEST_BUNDLE_LOC="${CMP_TEST_BUNDLE_LOC}"
+ INSTALL_AND_START_BUNDLES_CONFIG_PROPERTIES_FILE="${CMAKE_CURRENT_BINARY_DIR}/install_and_start_bundles.properties"
+ )
+ add_test(NAME test_framework_with_cxx14 COMMAND test_framework_with_cxx14)
+ setup_target_for_coverage(test_framework_with_cxx14 SCAN_DIR ..)
+endif ()
diff --git a/libs/framework/gtest/src/CxxBundleContextTestSuite.cc b/libs/framework/gtest/src/CxxBundleContextTestSuite.cc
index fe015185..dabc4288 100644
--- a/libs/framework/gtest/src/CxxBundleContextTestSuite.cc
+++ b/libs/framework/gtest/src/CxxBundleContextTestSuite.cc
@@ -715,6 +715,7 @@ TEST_F(CxxBundleContextTestSuite, GetBundleInformation) {
EXPECT_TRUE(startCalled);
}
+#if __cplusplus >= 201703L //C++17 or higher
class TestInterfaceWithStaticInfo {
public:
static constexpr std::string_view NAME = "TestName";
@@ -727,7 +728,7 @@ TEST_F(CxxBundleContextTestSuite, RegisterServiceWithNameAndVersionInfo) {
EXPECT_EQ(reg->getServiceName(), "TestName");
EXPECT_EQ(reg->getServiceVersion(), "1.2.3");
}
-
+#endif
TEST_F(CxxBundleContextTestSuite, listBundles) {
auto list = ctx->listBundleIds();
diff --git a/libs/framework/include/celix/Bundle.h b/libs/framework/include/celix/Bundle.h
index 90e31be4..4bc09ad8 100644
--- a/libs/framework/include/celix/Bundle.h
+++ b/libs/framework/include/celix/Bundle.h
@@ -64,25 +64,32 @@ namespace celix {
* @param path The relative path to a bundle resource
* @return The use-able entry path or an empty string if the entry is not found.
*/
+#if __cplusplus >= 201703L //C++17 or higher
[[nodiscard]] std::string getEntry(std::string_view path) const {
- std::string result{};
- char* entry = celix_bundle_getEntry(cBnd.get(), path.data());
- if (entry != nullptr) {
- result = std::string{entry};
- free(entry);
- }
- return result;
+ return getEntryInternal(path.data());
+ }
+#else
+ std::string getEntry(const std::string& path) const {
+ return getEntryInternal(path.c_str());
}
+#endif
/**
* @brief Get a manifest attribute value from the bundle manifest.
* @param attribute The attribute to get the value from.
* @return The attribute value or an empty string if the attribute is not present in the bundle manifest.
*/
+#if __cplusplus >= 201703L //C++17 or higher
[[nodiscard]] std::string getManifestValue(std::string_view attribute) const {
const char* header = celix_bundle_getManifestValue(cBnd.get(), attribute.data());
return header == nullptr ? std::string{} : std::string{header};
}
+#else
+ [[nodiscard]] std::string getManifestValue(const std::string& attribute) const {
+ const char* header = celix_bundle_getManifestValue(cBnd.get(), attribute.c_str());
+ return header == nullptr ? std::string{} : std::string{header};
+ }
+#endif
/**
* @brief the symbolic name of the bundle.
@@ -143,6 +150,17 @@ namespace celix {
return celix_bundle_isSystemBundle(cBnd.get());
}
private:
+ std::string getEntryInternal(const char* path) const {
+ std::string result{};
+ char* entry = celix_bundle_getEntry(cBnd.get(), path);
+ if (entry != nullptr) {
+ result = std::string{entry};
+ free(entry);
+ }
+ return result;
+ }
+
+
const std::shared_ptr<celix_bundle_t> cBnd;
};
}
diff --git a/libs/framework/include/celix/BundleActivator.h b/libs/framework/include/celix/BundleActivator.h
index 267777c8..1656db26 100644
--- a/libs/framework/include/celix/BundleActivator.h
+++ b/libs/framework/include/celix/BundleActivator.h
@@ -24,10 +24,10 @@
#include "celix/dm/DependencyManager.h"
#include "celix_bundle_activator.h"
-#if __cplusplus >= 201703L //C++17 or higher
+#if __cplusplus >= 201402L //C++14 or higher
#include "celix/BundleContext.h"
-
-namespace celix::impl {
+namespace celix {
+namespace impl {
template<typename I>
struct BundleActivatorData {
long bndId{};
@@ -94,7 +94,7 @@ namespace celix::impl {
waitForExpired(bndId, ctx, "celix::dm::DependencyManager", dm);
return CELIX_SUCCESS;
}
-}
+}}
#else //C++11
namespace celix {
namespace impl {
diff --git a/libs/framework/include/celix/BundleContext.h b/libs/framework/include/celix/BundleContext.h
index bbbc8ffb..20af2000 100644
--- a/libs/framework/include/celix/BundleContext.h
+++ b/libs/framework/include/celix/BundleContext.h
@@ -78,11 +78,19 @@ namespace celix {
* @param name The optional name of the service. If not provided celix::typeName<I> will be used to defer the service name.
* @return A ServiceRegistrationBuilder object.
*/
+#if __cplusplus >= 201703L //C++17 or higher
template<typename I, typename Implementer>
ServiceRegistrationBuilder<I> registerService(std::shared_ptr<Implementer> implementer, std::string_view name = {}) {
std::shared_ptr<I> svc = implementer; //note Implement should be derived from I
return ServiceRegistrationBuilder<I>{cCtx, std::move(svc), celix::typeName<I>(name)};
}
+#else
+ template<typename I, typename Implementer>
+ ServiceRegistrationBuilder<I> registerService(std::shared_ptr<Implementer> implementer, const std::string& name = {}) {
+ std::shared_ptr<I> svc = implementer; //note Implement should be derived from I
+ return ServiceRegistrationBuilder<I>{cCtx, std::move(svc), celix::typeName<I>(name)};
+ }
+#endif
/**
* @brief Register a (unmanaged) service in the Celix framework using a fluent builder API.
@@ -94,11 +102,19 @@ namespace celix {
* By default the service registration is configure to register the service async, but to unregister the
* service sync (because the svc pointer is unmanaged).
*/
+#if __cplusplus >= 201703L //C++17 or higher
template<typename I, typename Implementer>
ServiceRegistrationBuilder<I> registerUnmanagedService(Implementer* svc, std::string_view name = {}) {
auto unmanagedSvc = std::shared_ptr<I>{svc, [](I*){/*nop*/}};
return ServiceRegistrationBuilder<I>{cCtx, std::move(unmanagedSvc), celix::typeName<I>(name), true, false};
}
+#else
+ template<typename I, typename Implementer>
+ ServiceRegistrationBuilder<I> registerUnmanagedService(Implementer* svc, const std::string& name = {}) {
+ auto unmanagedSvc = std::shared_ptr<I>{svc, [](I*){/*nop*/}};
+ return ServiceRegistrationBuilder<I>{cCtx, std::move(unmanagedSvc), celix::typeName<I>(name), true, false};
+ }
+#endif
//TODO registerServiceFactory<I>()
@@ -128,10 +144,17 @@ namespace celix {
* @param name The optional service name to use. If not provided celix::typeName<I> will be used to defer the service name.
* @return A UseServiceBuilder object.
*/
+#if __cplusplus >= 201703L //C++17 or higher
template<typename I>
UseServiceBuilder<I> useService(std::string_view name = {}) {
return UseServiceBuilder<I>{cCtx, celix::typeName<I>(name), true};
}
+#else
+ template<typename I>
+ UseServiceBuilder<I> useService(const std::string& name = {}) {
+ return UseServiceBuilder<I>{cCtx, celix::typeName<I>(name), true};
+ }
+#endif
/**
* @brief Use services registered in the Celix framework using a fluent builder API.
@@ -156,10 +179,17 @@ namespace celix {
* @param name The optional service name to use. If not provided celix::typeName<I> will be used to defer the service name.
* @return A UseServiceBuilder object.
*/
+#if __cplusplus >= 201703L //C++17 or higher
template<typename I>
UseServiceBuilder<I> useServices(std::string_view name = {}) {
return UseServiceBuilder<I>{cCtx, celix::typeName<I>(name), false};
}
+#else
+ template<typename I>
+ UseServiceBuilder<I> useServices(const std::string& name = {}) {
+ return UseServiceBuilder<I>{cCtx, celix::typeName<I>(name), false};
+ }
+#endif
/**
* @brief Finds the highest ranking service using the optional provided (LDAP) filter
@@ -172,10 +202,17 @@ namespace celix {
* @param versionRange An optional version range.
* @return The service id of the found service or -1 if the service was not found.
*/
+#if __cplusplus >= 201703L //C++17 or higher
template<typename I>
long findService(std::string_view filter = {}, std::string_view versionRange = {}) {
return findServiceWithName(celix::typeName<I>(), filter, versionRange);
}
+#else
+ template<typename I>
+ long findService(const std::string& filter = {}, const std::string& versionRange = {}) {
+ return findServiceWithName(celix::typeName<I>(), filter, versionRange);
+ }
+#endif
/**
* @brief Finds the highest ranking service using the provided service name and
@@ -186,6 +223,7 @@ namespace celix {
* @param versionRange An optional version range.
* @return The service id of the found service or -1 if the service was not found.
*/
+#if __cplusplus >= 201703L //C++17 or higher
long findServiceWithName(std::string_view name, std::string_view filter = {}, std::string_view versionRange = {}) {
waitIfAbleForEvents();
celix_service_filter_options_t opts{};
@@ -194,6 +232,16 @@ namespace celix {
opts.versionRange = versionRange.empty() ? nullptr : versionRange.data();
return celix_bundleContext_findServiceWithOptions(cCtx.get(), &opts);
}
+#else
+ long findServiceWithName(const std::string& name, const std::string& filter = {}, const std::string& versionRange = {}) {
+ waitIfAbleForEvents();
+ celix_service_filter_options_t opts{};
+ opts.serviceName = name.empty() ? nullptr : name.data();
+ opts.filter = filter.empty() ? nullptr : filter.data();
+ opts.versionRange = versionRange.empty() ? nullptr : versionRange.data();
+ return celix_bundleContext_findServiceWithOptions(cCtx.get(), &opts);
+ }
+#endif
/**
* @brief Finds all services matching the optional provided (LDAP) filter
@@ -206,10 +254,17 @@ namespace celix {
* @param versionRange An optional version range.
* @return A vector of service ids.
*/
+#if __cplusplus >= 201703L //C++17 or higher
template<typename I>
std::vector<long> findServices(std::string_view filter = {}, std::string_view versionRange = {}) {
return findServicesWithName(celix::typeName<I>(), filter, versionRange);
}
+#else
+ template<typename I>
+ std::vector<long> findServices(const std::string& filter = {}, const std::string& versionRange = {}) {
+ return findServicesWithName(celix::typeName<I>(), filter, versionRange);
+ }
+#endif
/**
* @brief Finds all service matching the provided service name and the optional (LDAP) filter
@@ -220,22 +275,21 @@ namespace celix {
* @param versionRange An optional version range.
* @return A vector of service ids.
*/
+#if __cplusplus >= 201703L //C++17 or higher
std::vector<long> findServicesWithName(std::string_view name, std::string_view filter = {}, std::string_view versionRange = {}) {
- waitIfAbleForEvents();
- celix_service_filter_options_t opts{};
- opts.serviceName = name.empty() ? nullptr : name.data();
- opts.filter = filter.empty() ? nullptr : filter.data();
- opts.versionRange = versionRange.empty() ? nullptr : versionRange.data();
-
- std::vector<long> result{};
- auto cList = celix_bundleContext_findServicesWithOptions(cCtx.get(), &opts);
- for (int i = 0; i < celix_arrayList_size(cList); ++i) {
- long svcId = celix_arrayList_getLong(cList, i);
- result.push_back(svcId);
- }
- celix_arrayList_destroy(cList);
- return result;
+ return findServicesWithNameInternal(
+ name.empty() ? nullptr : name.data(),
+ filter.empty() ? nullptr : filter.data(),
+ versionRange.empty() ? nullptr : versionRange.data());
+ }
+#else
+ std::vector<long> findServicesWithName(const std::string& name, const std::string& filter = {}, const std::string& versionRange = {}) {
+ return findServicesWithNameInternal(
+ name.empty() ? nullptr : name.c_str(),
+ filter.empty() ? nullptr : filter.c_str(),
+ versionRange.empty() ? nullptr : versionRange.c_str());
}
+#endif
/**
* @brief Track services in the Celix framework using a fluent builder API.
@@ -257,10 +311,17 @@ namespace celix {
* @param name The optional service name. If empty celix::typeName<I> will be used to defer the service name.
* @return A ServiceTrackerBuilder object.
*/
+#if __cplusplus >= 201703L //C++17 or higher
template<typename I>
ServiceTrackerBuilder<I> trackServices(std::string_view name = {}) {
return ServiceTrackerBuilder<I>{cCtx, celix::typeName<I>(name)};
}
+#else
+ template<typename I>
+ ServiceTrackerBuilder<I> trackServices(const std::string& name = {}) {
+ return ServiceTrackerBuilder<I>{cCtx, celix::typeName<I>(name)};
+ }
+#endif
/**
* @brief Track services in the Celix framework using a fluent builder API.
@@ -310,10 +371,17 @@ namespace celix {
* @param name The optional service name. If empty celix::typeName<I> will be used to defer the service name.
* @return A MetaTrackerBuilder object.
*/
+#if __cplusplus >= 201703L //C++17 or higher
template<typename I>
MetaTrackerBuilder trackServiceTrackers(std::string_view name = {}) {
return MetaTrackerBuilder(cCtx, celix::typeName<I>(name));
}
+#else
+ template<typename I>
+ MetaTrackerBuilder trackServiceTrackers(const std::string& name = {}) {
+ return MetaTrackerBuilder(cCtx, celix::typeName<I>(name));
+ }
+#endif
/**
* @brief Track service trackers in the Celix framework using a fluent builder API.
@@ -333,9 +401,15 @@ namespace celix {
* @param autoStart If the bundle should also be started.
* @return the bundleId (>= 0) or < 0 if the bundle could not be installed and possibly started.
*/
+#if __cplusplus >= 201703L //C++17 or higher
long installBundle(std::string_view bndLocation, bool autoStart = true) {
return celix_bundleContext_installBundle(cCtx.get(), bndLocation.data(), autoStart);
}
+#else
+ long installBundle(const std::string& bndLocation, bool autoStart = true) {
+ return celix_bundleContext_installBundle(cCtx.get(), bndLocation.c_str(), autoStart);
+ }
+#endif
/**
* @brief Uninstall the bundle with the provided bundle id.
@@ -405,9 +479,15 @@ namespace celix {
* @param defaultVal The default value to use if the property is not found.
* @return The config property value for the provided key or the provided defaultValue is the name is not found.
*/
+#if __cplusplus >= 201703L //C++17 or higher
[[nodiscard]] std::string getConfigProperty(std::string_view name, std::string_view defaultValue) const {
return std::string{celix_bundleContext_getProperty(cCtx.get(), name.data(), defaultValue.data())};
}
+#else
+ std::string getConfigProperty(const std::string& name, const std::string& defaultValue) const {
+ return std::string{celix_bundleContext_getProperty(cCtx.get(), name.c_str(), defaultValue.c_str())};
+ }
+#endif
/**
* @brief Gets the config property for the provided name and returns it as a long.
@@ -421,9 +501,15 @@ namespace celix {
* @return The config property value (as long) for the provided key or the provided defaultValue is the name
* is not found or not a valid long.
*/
+#if __cplusplus >= 201703L //C++17 or higher
[[nodiscard]] long getConfigPropertyAsLong(std::string_view name, long defaultValue) const {
return celix_bundleContext_getPropertyAsLong(cCtx.get(), name.data(), defaultValue);
}
+#else
+ long getConfigPropertyAsLong(const std::string& name, long defaultValue) const {
+ return celix_bundleContext_getPropertyAsLong(cCtx.get(), name.c_str(), defaultValue);
+ }
+#endif
/**
* @brief Gets the config property for the provided name and returns it as a double.
@@ -437,9 +523,15 @@ namespace celix {
* @return The config property value (as double) for the provided key or the provided defaultValue is the name
* is not found or not a valid double.
*/
+#if __cplusplus >= 201703L //C++17 or higher
[[nodiscard]] double getConfigPropertyAsDouble(std::string_view name, double defaultValue) const {
return celix_bundleContext_getPropertyAsDouble(cCtx.get(), name.data(), defaultValue);
}
+#else
+ double getConfigPropertyAsDouble(const std::string& name, double defaultValue) const {
+ return celix_bundleContext_getPropertyAsDouble(cCtx.get(), name.c_str(), defaultValue);
+ }
+#endif
/**
* @brief Gets the config property for the provided name and returns it as a bool.
@@ -455,9 +547,15 @@ namespace celix {
* @return The config property value (as boolean) for the provided key or the provided defaultValue is the name
* is not found or not a valid boolean.
*/
+#if __cplusplus >= 201703L //C++17 or higher
[[nodiscard]] long getConfigPropertyAsBool(std::string_view name, bool defaultValue) const {
return celix_bundleContext_getPropertyAsBool(cCtx.get(), name.data(), defaultValue);
}
+#else
+ long getConfigPropertyAsBool(const std::string& name, bool defaultValue) const {
+ return celix_bundleContext_getPropertyAsBool(cCtx.get(), name.c_str(), defaultValue);
+ }
+#endif
/**
* @brief Get the bundle of this bundle context.
@@ -619,6 +717,23 @@ namespace celix {
return result;
}
+ std::vector<long> findServicesWithNameInternal(const char* name, const char* filter, const char* versionRange) {
+ waitIfAbleForEvents();
+ celix_service_filter_options_t opts{};
+ opts.serviceName = name;
+ opts.filter = filter;
+ opts.versionRange = versionRange;
+
+ std::vector<long> result{};
+ auto cList = celix_bundleContext_findServicesWithOptions(cCtx.get(), &opts);
+ for (int i = 0; i < celix_arrayList_size(cList); ++i) {
+ long svcId = celix_arrayList_getLong(cList, i);
+ result.push_back(svcId);
+ }
+ celix_arrayList_destroy(cList);
+ return result;
+ }
+
const std::shared_ptr<celix_bundle_context_t> cCtx;
const std::shared_ptr<celix::dm::DependencyManager> dm;
const Bundle bnd;
diff --git a/libs/framework/include/celix/ServiceRegistration.h b/libs/framework/include/celix/ServiceRegistration.h
index 3b077365..6f7b4f0a 100644
--- a/libs/framework/include/celix/ServiceRegistration.h
+++ b/libs/framework/include/celix/ServiceRegistration.h
@@ -67,6 +67,7 @@ namespace celix {
* @return The new ServiceRegistration object as shared ptr.
* @throws celix::Exception
*/
+#if __cplusplus >= 201703L //C++17 or higher
static std::shared_ptr<ServiceRegistration> create(std::shared_ptr<celix_bundle_context_t> cCtx,
std::shared_ptr<void> svc,
std::string_view name,
@@ -76,54 +77,25 @@ namespace celix {
bool unregisterAsync,
std::vector<std::function<void(ServiceRegistration&)>> onRegisteredCallbacks,
std::vector<std::function<void(ServiceRegistration&)>> onUnregisteredCallbacks) {
- auto delCallback = [](ServiceRegistration* reg) {
- if (reg->getState() == ServiceRegistrationState::UNREGISTERED) {
- delete reg;
- } else {
- /*
- * if not registered/unregistering -> unregister() -> new event on the Celix event thread
- * if unregistering -> nop unregister() -> there is already a event on the Celix event thread to unregister
- */
- reg->unregister();
-
- /*
- * Creating event on the Event loop, this will be after the unregistration is done
- */
- auto* fw = celix_bundleContext_getFramework(reg->cCtx.get());
- auto* bnd = celix_bundleContext_getBundle(reg->cCtx.get());
- long bndId = celix_bundle_getId(bnd);
- celix_framework_fireGenericEvent(
- fw,
- -1,
- bndId,
- "celix::ServiceRegistration delete callback",
- reg,
- [](void *data) {
- auto* r = static_cast<ServiceRegistration*>(data);
- delete r;
- },
- nullptr,
- nullptr);
- }
- };
-
- auto reg = std::shared_ptr<ServiceRegistration>{
- new ServiceRegistration{
- std::move(cCtx),
- std::move(svc),
- name,
- version,
- std::move(properties),
- registerAsync,
- unregisterAsync,
- std::move(onRegisteredCallbacks),
- std::move(onUnregisteredCallbacks)},
- delCallback
- };
- reg->setSelf(reg);
- reg->registerService();
- return reg;
+ return createInternal(std::move(cCtx), std::move(svc), name.data(),
+ version.data(), std::move(properties), registerAsync,
+ unregisterAsync, std::move(onRegisteredCallbacks), std::move(onUnregisteredCallbacks));
}
+#else
+ static std::shared_ptr<ServiceRegistration> create(std::shared_ptr<celix_bundle_context_t> cCtx,
+ std::shared_ptr<void> svc,
+ const std::string& name,
+ const std::string& version,
+ celix::Properties properties,
+ bool registerAsync,
+ bool unregisterAsync,
+ std::vector<std::function<void(ServiceRegistration&)>> onRegisteredCallbacks,
+ std::vector<std::function<void(ServiceRegistration&)>> onUnregisteredCallbacks) {
+ return createInternal(std::move(cCtx), std::move(svc), name.c_str(),
+ version.c_str(), std::move(properties), registerAsync,
+ unregisterAsync, std::move(onRegisteredCallbacks), std::move(onUnregisteredCallbacks));
+ }
+#endif
/**
* @brief The service name for this service registration.
@@ -256,8 +228,8 @@ namespace celix {
ServiceRegistration(
std::shared_ptr<celix_bundle_context_t> _cCtx,
std::shared_ptr<void> _svc,
- std::string_view _name,
- std::string_view _version,
+ const char* _name,
+ const char* _version,
celix::Properties _properties,
bool _registerAsync,
bool _unregisterAsync,
@@ -273,6 +245,64 @@ namespace celix {
onUnregisteredCallbacks{std::move(_onUnregisteredCallbacks)},
svc{std::move(_svc)} {}
+ static std::shared_ptr<ServiceRegistration> createInternal(
+ std::shared_ptr<celix_bundle_context_t> cCtx,
+ std::shared_ptr<void> svc,
+ const char* name,
+ const char* version,
+ celix::Properties properties,
+ bool registerAsync,
+ bool unregisterAsync,
+ std::vector<std::function<void(ServiceRegistration&)>> onRegisteredCallbacks,
+ std::vector<std::function<void(ServiceRegistration&)>> onUnregisteredCallbacks) {
+ auto delCallback = [](ServiceRegistration* reg) {
+ if (reg->getState() == ServiceRegistrationState::UNREGISTERED) {
+ delete reg;
+ } else {
+ /*
+ * if not registered/unregistering -> unregister() -> new event on the Celix event thread
+ * if unregistering -> nop unregister() -> there is already a event on the Celix event thread to unregister
+ */
+ reg->unregister();
+
+ /*
+ * Creating event on the Event loop, this will be after the unregistration is done
+ */
+ auto* fw = celix_bundleContext_getFramework(reg->cCtx.get());
+ auto* bnd = celix_bundleContext_getBundle(reg->cCtx.get());
+ long bndId = celix_bundle_getId(bnd);
+ celix_framework_fireGenericEvent(
+ fw,
+ -1,
+ bndId,
+ "celix::ServiceRegistration delete callback",
+ reg,
+ [](void *data) {
+ auto* r = static_cast<ServiceRegistration*>(data);
+ delete r;
+ },
+ nullptr,
+ nullptr);
+ }
+ };
+
+ auto reg = std::shared_ptr<ServiceRegistration>{
+ new ServiceRegistration{
+ std::move(cCtx),
+ std::move(svc),
+ name,
+ version,
+ std::move(properties),
+ registerAsync,
+ unregisterAsync,
+ std::move(onRegisteredCallbacks),
+ std::move(onUnregisteredCallbacks)},
+ delCallback
+ };
+ reg->setSelf(reg);
+ reg->registerService();
+ return reg;
+ }
/**
* @brief Register service in the Celix framework.
diff --git a/libs/framework/include/celix/ServiceRegistrationBuilder.h b/libs/framework/include/celix/ServiceRegistrationBuilder.h
index 54bbd0e7..a05de383 100644
--- a/libs/framework/include/celix/ServiceRegistrationBuilder.h
+++ b/libs/framework/include/celix/ServiceRegistrationBuilder.h
@@ -45,15 +45,15 @@ namespace celix {
ServiceRegistrationBuilder(
std::shared_ptr<celix_bundle_context_t> _cCtx,
std::shared_ptr<I> _svc,
- std::string_view _name,
+ std::string _name,
bool _registerAsync = true,
bool _unregisterAsync = true) :
cCtx{std::move(_cCtx)},
svc{std::move(_svc)},
- name{_name},
+ name{std::move(_name)},
version{celix::typeVersion<I>()},
registerAsync{_registerAsync},
- unregisterAsync{_unregisterAsync}{}
+ unregisterAsync{_unregisterAsync} {}
ServiceRegistrationBuilder& operator=(ServiceRegistrationBuilder&&) = delete;
ServiceRegistrationBuilder(const ServiceRegistrationBuilder&) = delete;
@@ -64,15 +64,24 @@ namespace celix {
*
* This will lead to a 'service.version' service property.
*/
+#if __cplusplus >= 201703L //C++17 or higher
ServiceRegistrationBuilder& setVersion(std::string_view v) { version = v; return *this; }
+#else
+ ServiceRegistrationBuilder& setVersion(std::string v) { version = std::move(v); return *this; }
+#endif
/**
* @brief Add a property to the service properties.
*
* If a key is already present the value will be overridden.
*/
+#if __cplusplus >= 201703L //C++17 or higher
template<typename T>
ServiceRegistrationBuilder& addProperty(std::string_view key, T&& value) { properties.template set(key, std::forward<T>(value)); return *this; }
+#else
+ template<typename T>
+ ServiceRegistrationBuilder& addProperty(const std::string& key, T&& value) { properties.template set(key, std::forward<T>(value)); return *this; }
+#endif
/**
* @brief Set the service properties.
diff --git a/libs/framework/include/celix/TrackerBuilders.h b/libs/framework/include/celix/TrackerBuilders.h
index bec73086..35883d82 100644
--- a/libs/framework/include/celix/TrackerBuilders.h
+++ b/libs/framework/include/celix/TrackerBuilders.h
@@ -42,9 +42,9 @@ namespace celix {
//NOTE private to prevent move so that a build() call cannot be forgotten
ServiceTrackerBuilder(ServiceTrackerBuilder&&) noexcept = default;
public:
- explicit ServiceTrackerBuilder(std::shared_ptr<celix_bundle_context_t> _cCtx, std::string_view _name) :
+ explicit ServiceTrackerBuilder(std::shared_ptr<celix_bundle_context_t> _cCtx, std::string _name) :
cCtx{std::move(_cCtx)},
- name{_name} {}
+ name{std::move(_name)} {}
ServiceTrackerBuilder& operator=(ServiceTrackerBuilder&&) = delete;
ServiceTrackerBuilder(const ServiceTrackerBuilder&) = delete;
@@ -57,7 +57,11 @@ namespace celix {
* Example:
* "(property_key=value)"
*/
+#if __cplusplus >= 201703L //C++17 or higher
ServiceTrackerBuilder& setFilter(std::string_view f) { filter = celix::Filter{f}; return *this; }
+#else
+ ServiceTrackerBuilder& setFilter(const std::string& f) { filter = celix::Filter{f}; return *this; }
+#endif
/**
* @brief Set filter to be used to matching services.
@@ -310,10 +314,9 @@ namespace celix {
//NOTE private to prevent move so that a build() call cannot be forgotten
MetaTrackerBuilder(MetaTrackerBuilder &&) = default;
public:
- explicit MetaTrackerBuilder(std::shared_ptr<celix_bundle_context_t> _cCtx, std::string_view _serviceName) :
+ explicit MetaTrackerBuilder(std::shared_ptr<celix_bundle_context_t> _cCtx, std::string _serviceName) :
cCtx{std::move(_cCtx)},
- serviceName{_serviceName}
- {}
+ serviceName{std::move(_serviceName)} {}
MetaTrackerBuilder &operator=(MetaTrackerBuilder &&) = delete;
MetaTrackerBuilder(const MetaTrackerBuilder &) = delete;
diff --git a/libs/framework/include/celix/Trackers.h b/libs/framework/include/celix/Trackers.h
index 4a2b491e..cd99ecf3 100644
--- a/libs/framework/include/celix/Trackers.h
+++ b/libs/framework/include/celix/Trackers.h
@@ -217,18 +217,19 @@ namespace celix {
*/
class GenericServiceTracker : public AbstractTracker {
public:
+#if __cplusplus >= 201703L //C++17 or higher
GenericServiceTracker(std::shared_ptr<celix_bundle_context_t> _cCtx, std::string_view _svcName,
std::string_view _svcVersionRange, celix::Filter _filter) : AbstractTracker{std::move(_cCtx)}, svcName{_svcName},
svcVersionRange{_svcVersionRange}, filter{std::move(_filter)} {
- opts.trackerCreatedCallbackData = this;
- opts.trackerCreatedCallback = [](void *data) {
- auto* trk = static_cast<GenericServiceTracker*>(data);
- {
- std::lock_guard<std::mutex> callbackLock{trk->mutex};
- trk->state = TrackerState::OPEN;
- }
- };
+ setupServiceTrackerOptions();
+ }
+#else
+ GenericServiceTracker(std::shared_ptr<celix_bundle_context_t> _cCtx, std::string _svcName,
+ std::string _svcVersionRange, celix::Filter _filter) : AbstractTracker{std::move(_cCtx)}, svcName{std::move(_svcName)},
+ svcVersionRange{std::move(_svcVersionRange)}, filter{std::move(_filter)} {
+ setupServiceTrackerOptions();
}
+#endif
~GenericServiceTracker() override = default;
@@ -278,6 +279,18 @@ namespace celix {
const celix::Filter filter;
celix_service_tracking_options opts{}; //note only set in the ctor
std::atomic<size_t> svcCount{0};
+
+ private:
+ void setupServiceTrackerOptions() {
+ opts.trackerCreatedCallbackData = this;
+ opts.trackerCreatedCallback = [](void *data) {
+ auto* trk = static_cast<GenericServiceTracker*>(data);
+ {
+ std::lock_guard<std::mutex> callbackLock{trk->mutex};
+ trk->state = TrackerState::OPEN;
+ }
+ };
+ }
};
/**
@@ -307,6 +320,7 @@ namespace celix {
* @return The new service tracker as shared ptr.
* @throws celix::Exception
*/
+#if __cplusplus >= 201703L //C++17 or higher
static std::shared_ptr<ServiceTracker<I>> create(
std::shared_ptr<celix_bundle_context_t> cCtx,
std::string_view svcName,
@@ -315,7 +329,6 @@ namespace celix {
std::vector<std::function<void(const std::shared_ptr<I>&, const std::shared_ptr<const celix::Properties>&, const std::shared_ptr<const celix::Bundle>&)>> setCallbacks,
std::vector<std::function<void(const std::shared_ptr<I>&, const std::shared_ptr<const celix::Properties>&, const std::shared_ptr<const celix::Bundle>&)>> addCallbacks,
std::vector<std::function<void(const std::shared_ptr<I>&, const std::shared_ptr<const celix::Properties>&, const std::shared_ptr<const celix::Bundle>&)>> remCallbacks) {
-
auto tracker = std::shared_ptr<ServiceTracker<I>>{
new ServiceTracker<I>{
std::move(cCtx),
@@ -329,6 +342,29 @@ namespace celix {
tracker->open();
return tracker;
}
+#else
+ static std::shared_ptr<ServiceTracker<I>> create(
+ std::shared_ptr<celix_bundle_context_t> cCtx,
+ std::string svcName,
+ std::string svcVersionRange,
+ celix::Filter filter,
+ std::vector<std::function<void(const std::shared_ptr<I>&, const std::shared_ptr<const celix::Properties>&, const std::shared_ptr<const celix::Bundle>&)>> setCallbacks,
+ std::vector<std::function<void(const std::shared_ptr<I>&, const std::shared_ptr<const celix::Properties>&, const std::shared_ptr<const celix::Bundle>&)>> addCallbacks,
+ std::vector<std::function<void(const std::shared_ptr<I>&, const std::shared_ptr<const celix::Properties>&, const std::shared_ptr<const celix::Bundle>&)>> remCallbacks) {
+ auto tracker = std::shared_ptr<ServiceTracker<I>>{
+ new ServiceTracker<I>{
+ std::move(cCtx),
+ std::move(svcName),
+ std::move(svcVersionRange),
+ std::move(filter),
+ std::move(setCallbacks),
+ std::move(addCallbacks),
+ std::move(remCallbacks)},
+ AbstractTracker::delCallback<ServiceTracker<I>>()};
+ tracker->open();
+ return tracker;
+ }
+#endif
/**
* @brief Get the current highest ranking service tracked by this tracker.
@@ -382,6 +418,7 @@ namespace celix {
std::shared_ptr<const celix::Bundle> owner;
};
+#if __cplusplus >= 201703L //C++17 or higher
ServiceTracker(std::shared_ptr<celix_bundle_context_t> _cCtx, std::string_view _svcName,
std::string_view _svcVersionRange, celix::Filter _filter,
std::vector<std::function<void(const std::shared_ptr<I>&, const std::shared_ptr<const celix::Properties>&, const std::shared_ptr<const celix::Bundle>&)>> _setCallbacks,
@@ -391,63 +428,21 @@ namespace celix {
setCallbacks{std::move(_setCallbacks)},
addCallbacks{std::move(_addCallbacks)},
remCallbacks{std::move(_remCallbacks)} {
- opts.filter.serviceName = svcName.empty() ? nullptr : svcName.c_str();
- opts.filter.versionRange = svcVersionRange.empty() ? nullptr : svcVersionRange.c_str();
- opts.filter.filter = filter.empty() ? nullptr : filter.getFilterCString();
- opts.callbackHandle = this;
- opts.addWithOwner = [](void *handle, void *voidSvc, const celix_properties_t* cProps, const celix_bundle_t* cBnd) {
- auto tracker = static_cast<ServiceTracker<I>*>(handle);
- auto entry = createEntry(voidSvc, cProps, cBnd);
- {
- std::lock_guard<std::mutex> lck{tracker->mutex};
- tracker->entries.insert(entry);
- tracker->cachedEntries[entry->svcId] = entry;
- }
- tracker->svcCount.fetch_add(1, std::memory_order_relaxed);
- for (const auto& cb : tracker->addCallbacks) {
- cb(entry->svc, entry->properties, entry->owner);
- }
- tracker->invokeUpdateCallbacks();
- };
- opts.removeWithOwner = [](void *handle, void*, const celix_properties_t* cProps, const celix_bundle_t*) {
- auto tracker = static_cast<ServiceTracker<I>*>(handle);
- long svcId = celix_properties_getAsLong(cProps, OSGI_FRAMEWORK_SERVICE_ID, -1L);
- std::shared_ptr<SvcEntry> entry{};
- {
- std::lock_guard<std::mutex> lck{tracker->mutex};
- auto it = tracker->cachedEntries.find(svcId);
- assert(it != tracker->cachedEntries.end()); //should not happen, added during add callback
- entry = it->second;
- tracker->cachedEntries.erase(it);
- tracker->entries.erase(entry);
- }
- for (const auto& cb : tracker->remCallbacks) {
- cb(entry->svc, entry->properties, entry->owner);
- }
- tracker->invokeUpdateCallbacks();
- tracker->svcCount.fetch_sub(1, std::memory_order_relaxed);
- tracker->waitForExpiredSvcEntry(entry);
- };
- opts.setWithOwner = [](void *handle, void *voidSvc, const celix_properties_t *cProps, const celix_bundle_t *cBnd) {
- auto tracker = static_cast<ServiceTracker<I>*>(handle);
- std::lock_guard<std::mutex> lck{tracker->mutex};
- auto prevEntry = tracker->highestRankingServiceEntry;
- if (voidSvc) {
- tracker->highestRankingServiceEntry = createEntry(voidSvc, cProps, cBnd);
- } else {
- tracker->highestRankingServiceEntry = nullptr;
- }
- for (const auto& cb : tracker->setCallbacks) {
- if (tracker->highestRankingServiceEntry) {
- auto& e = tracker->highestRankingServiceEntry;
- cb(e->svc, e->properties, e->owner);
- } else /*"unset"*/ {
- cb(nullptr, nullptr, nullptr);
- }
- }
- tracker->waitForExpiredSvcEntry(prevEntry);
- };
+ setupServiceTrackerOptions();
+ }
+#else
+ ServiceTracker(std::shared_ptr<celix_bundle_context_t> _cCtx, std::string _svcName,
+ std::string _svcVersionRange, celix::Filter _filter,
+ std::vector<std::function<void(const std::shared_ptr<I>&, const std::shared_ptr<const celix::Properties>&, const std::shared_ptr<const celix::Bundle>&)>> _setCallbacks,
+ std::vector<std::function<void(const std::shared_ptr<I>&, const std::shared_ptr<const celix::Properties>&, const std::shared_ptr<const celix::Bundle>&)>> _addCallbacks,
+ std::vector<std::function<void(const std::shared_ptr<I>&, const std::shared_ptr<const celix::Properties>&, const std::shared_ptr<const celix::Bundle>&)>> _remCallbacks) :
+ GenericServiceTracker{std::move(_cCtx), std::move(_svcName), std::move(_svcVersionRange), std::move(_filter)},
+ setCallbacks{std::move(_setCallbacks)},
+ addCallbacks{std::move(_addCallbacks)},
+ remCallbacks{std::move(_remCallbacks)} {
+ setupServiceTrackerOptions();
}
+#endif
static std::shared_ptr<SvcEntry> createEntry(void* voidSvc, const celix_properties_t* cProps, const celix_bundle_t* cBnd) {
long svcId = celix_properties_getAsLong(cProps, OSGI_FRAMEWORK_SERVICE_ID, -1L);
@@ -550,6 +545,66 @@ namespace celix {
std::set<std::shared_ptr<SvcEntry>, SvcEntryCompare> entries{};
std::unordered_map<long, std::shared_ptr<SvcEntry>> cachedEntries{};
std::shared_ptr<SvcEntry> highestRankingServiceEntry{};
+
+ private:
+ void setupServiceTrackerOptions() {
+ opts.filter.serviceName = svcName.empty() ? nullptr : svcName.c_str();
+ opts.filter.versionRange = svcVersionRange.empty() ? nullptr : svcVersionRange.c_str();
+ opts.filter.filter = filter.empty() ? nullptr : filter.getFilterCString();
+ opts.callbackHandle = this;
+ opts.addWithOwner = [](void *handle, void *voidSvc, const celix_properties_t* cProps, const celix_bundle_t* cBnd) {
+ auto tracker = static_cast<ServiceTracker<I>*>(handle);
+ auto entry = createEntry(voidSvc, cProps, cBnd);
+ {
+ std::lock_guard<std::mutex> lck{tracker->mutex};
+ tracker->entries.insert(entry);
+ tracker->cachedEntries[entry->svcId] = entry;
+ }
+ tracker->svcCount.fetch_add(1, std::memory_order_relaxed);
+ for (const auto& cb : tracker->addCallbacks) {
+ cb(entry->svc, entry->properties, entry->owner);
+ }
+ tracker->invokeUpdateCallbacks();
+ };
+ opts.removeWithOwner = [](void *handle, void*, const celix_properties_t* cProps, const celix_bundle_t*) {
+ auto tracker = static_cast<ServiceTracker<I>*>(handle);
+ long svcId = celix_properties_getAsLong(cProps, OSGI_FRAMEWORK_SERVICE_ID, -1L);
+ std::shared_ptr<SvcEntry> entry{};
+ {
+ std::lock_guard<std::mutex> lck{tracker->mutex};
+ auto it = tracker->cachedEntries.find(svcId);
+ assert(it != tracker->cachedEntries.end()); //should not happen, added during add callback
+ entry = it->second;
+ tracker->cachedEntries.erase(it);
+ tracker->entries.erase(entry);
+ }
+ for (const auto& cb : tracker->remCallbacks) {
+ cb(entry->svc, entry->properties, entry->owner);
+ }
+ tracker->invokeUpdateCallbacks();
+ tracker->svcCount.fetch_sub(1, std::memory_order_relaxed);
+ tracker->waitForExpiredSvcEntry(entry);
+ };
+ opts.setWithOwner = [](void *handle, void *voidSvc, const celix_properties_t *cProps, const celix_bundle_t *cBnd) {
+ auto tracker = static_cast<ServiceTracker<I>*>(handle);
+ std::lock_guard<std::mutex> lck{tracker->mutex};
+ auto prevEntry = tracker->highestRankingServiceEntry;
+ if (voidSvc) {
+ tracker->highestRankingServiceEntry = createEntry(voidSvc, cProps, cBnd);
+ } else {
+ tracker->highestRankingServiceEntry = nullptr;
+ }
+ for (const auto& cb : tracker->setCallbacks) {
+ if (tracker->highestRankingServiceEntry) {
+ auto& e = tracker->highestRankingServiceEntry;
+ cb(e->svc, e->properties, e->owner);
+ } else /*"unset"*/ {
+ cb(nullptr, nullptr, nullptr);
+ }
+ }
+ tracker->waitForExpiredSvcEntry(prevEntry);
+ };
+ }
};
/**
@@ -695,22 +750,39 @@ namespace celix {
* @return The new meta tracker as shared ptr.
* @throws celix::Exception.
*/
+#if __cplusplus >= 201703L //C++17 or higher
static std::shared_ptr<MetaTracker> create(
std::shared_ptr<celix_bundle_context_t> cCtx,
std::string_view serviceName,
std::vector<std::function<void(const ServiceTrackerInfo&)>> onTrackerCreated,
std::vector<std::function<void(const ServiceTrackerInfo&)>> onTrackerDestroyed) {
-
auto tracker = std::shared_ptr<MetaTracker>{
new MetaTracker{
std::move(cCtx),
- serviceName,
+ std::string{serviceName},
+ std::move(onTrackerCreated),
+ std::move(onTrackerDestroyed)},
+ AbstractTracker::delCallback<MetaTracker>()};
+ tracker->open();
+ return tracker;
+ }
+#else
+ static std::shared_ptr<MetaTracker> create(
+ std::shared_ptr<celix_bundle_context_t> cCtx,
+ std::string serviceName,
+ std::vector<std::function<void(const ServiceTrackerInfo&)>> onTrackerCreated,
+ std::vector<std::function<void(const ServiceTrackerInfo&)>> onTrackerDestroyed) {
+ auto tracker = std::shared_ptr<MetaTracker>{
+ new MetaTracker{
+ std::move(cCtx),
+ std::move(serviceName),
std::move(onTrackerCreated),
std::move(onTrackerDestroyed)},
AbstractTracker::delCallback<MetaTracker>()};
tracker->open();
return tracker;
}
+#endif
/**
* @see AbstractTracker::open
@@ -756,11 +828,11 @@ namespace celix {
private:
MetaTracker(
std::shared_ptr<celix_bundle_context_t> _cCtx,
- std::string_view _serviceName,
+ std::string _serviceName,
std::vector<std::function<void(const ServiceTrackerInfo&)>> _onTrackerCreated,
std::vector<std::function<void(const ServiceTrackerInfo&)>> _onTrackerDestroyed) :
AbstractTracker{std::move(_cCtx)},
- serviceName{_serviceName},
+ serviceName{std::move(_serviceName)},
onTrackerCreated{std::move(_onTrackerCreated)},
onTrackerDestroyed{std::move(_onTrackerDestroyed)} {}
diff --git a/libs/framework/include/celix/UseServiceBuilder.h b/libs/framework/include/celix/UseServiceBuilder.h
index f6c6d11b..6aa8aa24 100644
--- a/libs/framework/include/celix/UseServiceBuilder.h
+++ b/libs/framework/include/celix/UseServiceBuilder.h
@@ -54,11 +54,10 @@ namespace celix {
//NOTE private to prevent move so that a build() call cannot be forgotten
UseServiceBuilder(UseServiceBuilder&&) noexcept = default;
public:
- explicit UseServiceBuilder(std::shared_ptr<celix_bundle_context_t> _cCtx, std::string_view _name, bool _useSingleService = true) :
+ explicit UseServiceBuilder(std::shared_ptr<celix_bundle_context_t> _cCtx, std::string _name, bool _useSingleService = true) :
cCtx{std::move(_cCtx)},
- name{_name},
- useSingleService{_useSingleService} {
- }
+ name{std::move(_name)},
+ useSingleService{_useSingleService} {}
UseServiceBuilder& operator=(UseServiceBuilder&&) = delete;
UseServiceBuilder(const UseServiceBuilder&) = delete;
@@ -71,7 +70,11 @@ namespace celix {
* Example:
* "(property_key=value)"
*/
+#if __cplusplus >= 201703L //C++17 or higher
UseServiceBuilder& setFilter(std::string_view f) { filter = celix::Filter{f}; return *this; }
+#else
+ UseServiceBuilder& setFilter(const std::string& f) { filter = celix::Filter{f}; return *this; }
+#endif
/**
* @brief Set filter to be used to matching services.
diff --git a/libs/utils/gtest/CMakeLists.txt b/libs/utils/gtest/CMakeLists.txt
index b021b326..466002dc 100644
--- a/libs/utils/gtest/CMakeLists.txt
+++ b/libs/utils/gtest/CMakeLists.txt
@@ -15,6 +15,11 @@
# specific language governing permissions and limitations
# under the License.
+set(CELIX_UTIL_TEST_SOURCES_FOR_CXX_HEADERS
+ src/CxxUtilsTestSuite.cc
+ src/CxxPropertiesTestSuite.cc
+ src/CxxFilterTestSuite.cc
+)
add_executable(test_utils
src/LogUtilsTestSuite.cc
@@ -23,9 +28,7 @@ add_executable(test_utils
src/HashMapTestSuite.cc
src/ArrayListTestSuite.cc
src/FileUtilsTestSuite.cc
- src/CxxUtilsTestSuite.cc
- src/CxxPropertiesTestSuite.cc
- src/CxxFilterTestSuite.cc
+ ${CELIX_UTIL_TEST_SOURCES_FOR_CXX_HEADERS}
)
target_link_libraries(test_utils PRIVATE Celix::utils GTest::gtest GTest::gtest_main)
@@ -66,14 +69,14 @@ endif ()
add_test(NAME test_utils COMMAND test_utils)
setup_target_for_coverage(test_utils SCAN_DIR ..)
-
-#Setting standard to C++11 and testing C++ Properties to ensure that this still support C++11.
-#Note that celix Properties are used in the C++11 dependency manager and this be backwards compatible with Celix 2.2.1
-set(CMAKE_CXX_STANDARD 11)
-add_executable(test_properties_with_cxx11
- src/CxxPropertiesTestSuite.cc
-)
-target_link_libraries(test_properties_with_cxx11 PRIVATE Celix::utils GTest::gtest GTest::gtest_main)
-add_test(NAME test_properties_with_cxx11 COMMAND test_properties_with_cxx11)
-setup_target_for_coverage(test_properties_with_cxx11 SCAN_DIR ..)
+if (CELIX_TEST_FOR_CXX14)
+ #Setting standard to C++14 and testing C++ Properties.h, Filter.h and Utils.h to ensure that C++14 is supported.
+ set(CMAKE_CXX_STANDARD 14)
+ add_executable(test_utils_cxx_headers_with_cxx14
+ ${CELIX_UTIL_TEST_SOURCES_FOR_CXX_HEADERS}
+ )
+ target_link_libraries(test_utils_cxx_headers_with_cxx14 PRIVATE Celix::utils GTest::gtest GTest::gtest_main)
+ add_test(NAME test_utils_cxx_headers_with_cxx14 COMMAND test_utils_cxx_headers_with_cxx14)
+ setup_target_for_coverage(test_utils_cxx_headers_with_cxx14 SCAN_DIR ..)
+endif ()
diff --git a/libs/utils/gtest/src/CxxUtilsTestSuite.cc b/libs/utils/gtest/src/CxxUtilsTestSuite.cc
index 11f21e99..4a051043 100644
--- a/libs/utils/gtest/src/CxxUtilsTestSuite.cc
+++ b/libs/utils/gtest/src/CxxUtilsTestSuite.cc
@@ -32,11 +32,13 @@ namespace example {
std::string VERSION; //dummy non-static VERSION member, should not impact the typeVersion call
};
+#if __cplusplus >= 201703L //C++17 or higher
class TestType2 {
public:
static constexpr std::string_view NAME = "AnotherTestTypeName";
static constexpr const char * const VERSION = "1.2.0";
};
+#endif
class TestType3 {
public:
@@ -52,20 +54,24 @@ TEST_F(CxxUtilsTestSuite, testTypeName) {
auto name = celix::typeName<example::TestType>();
EXPECT_FALSE(name.empty());
+#if __cplusplus >= 201703L //C++17 or higher
//When inferring a type name with no provided name, but the type has a NAME static member,
- //the call should return the string value of the NAME static member
+ //the call should return the string value of the NAME static member (only support if C++17 is used).
name = celix::typeName<example::TestType2>();
EXPECT_EQ(std::string{name}, std::string{"AnotherTestTypeName"});
+#endif
//When inferring a type name with a provided name and the type does not have a NAME static member,
//the call should return the provided name.
name = celix::typeName<example::TestType>("OverrideName");
EXPECT_EQ(name, std::string{"OverrideName"});
+#if __cplusplus >= 201703L //C++17 or higher
//When inferring a type name with a provided name and the type also has a NAME static member,
- //the call should return the provided name.
+ //the call should return the provided name (only support if C++17 is used).
name = celix::typeName<example::TestType2>("OverrideName");
EXPECT_EQ(name, std::string{"OverrideName"});
+#endif
//When inferring a type name, where there is a static NAME member but not of the right type (constructable from string),
//the call should return an inferred name based on __PRETTY_FUNCTION__ (see celix::impl::extractTypeName)
@@ -80,20 +86,24 @@ TEST_F(CxxUtilsTestSuite, testTypeVersion) {
auto version = celix::typeVersion<example::TestType>();
EXPECT_TRUE(version.empty());
+#if __cplusplus >= 201703L //C++17 or higher
//When inferring a type version with no provided version and the type has a VERSION static member,
- //the call should return the value of the static member VERSION.
+ //the call should return the value of the static member VERSION (only support if C++17 is used).
version = celix::typeVersion<example::TestType2>();
EXPECT_EQ(std::string{version}, std::string{"1.2.0"});
+#endif
//When inferring a type version with a provided version and the type does not have a VERSION static member,
//the call should return the provided version.
version = celix::typeVersion<example::TestType>("2.2.2");
EXPECT_EQ(version, std::string{"2.2.2"});
+#if __cplusplus >= 201703L //C++17 or higher
//When inferring a type version with a provided version and the type does have a VERSION static member,
- //the call should return the provided version.
+ //the call should return the provided version (only support if C++17 is used).
version = celix::typeVersion<example::TestType2>("2.2.2");
EXPECT_EQ(version, std::string{"2.2.2"});
+#endif
}
TEST_F(CxxUtilsTestSuite, testSplit) {
diff --git a/libs/utils/include/celix/Filter.h b/libs/utils/include/celix/Filter.h
index ab00ec94..b92890d9 100644
--- a/libs/utils/include/celix/Filter.h
+++ b/libs/utils/include/celix/Filter.h
@@ -59,16 +59,21 @@ namespace celix {
class Filter {
public:
Filter() : cFilter{createFilter("")} {}
- explicit Filter(std::string_view filterStr) : cFilter{createFilter(filterStr)} {}
+#if __cplusplus >= 201703L //C++17 or higher
+ explicit Filter(std::string_view filterStr) : cFilter{createFilter(filterStr.data())} {}
+#else
+ explicit Filter(const std::string& filterStr) : cFilter{createFilter(filterStr.c_str())} {}
+#endif
+
Filter(Filter&&) = default;
Filter& operator=(Filter&&) = default;
- Filter(const Filter& rhs) : cFilter{createFilter(rhs.getFilterString())} {}
+ Filter(const Filter& rhs) : cFilter{createFilter(rhs.getFilterString().c_str())} {}
Filter& operator=(const Filter& rhs) {
if (this != &rhs) {
- cFilter = createFilter(rhs.getFilterString());
+ cFilter = createFilter(rhs.getFilterString().c_str());
}
return *this;
}
@@ -107,17 +112,30 @@ namespace celix {
* @brief Find the attribute based on the provided key.
* @return The found attribute value or an empty string if the attribute was not found.
*/
+#if __cplusplus >= 201703L //C++17 or higher
[[nodiscard]] std::string findAttribute(std::string_view attributeKey) const {
auto* cValue = celix_filter_findAttribute(cFilter.get(), attributeKey.data());
return cValue == nullptr ? std::string{} : std::string{cValue};
}
+#else
+ std::string findAttribute(const std::string& attributeKey) const {
+ auto* cValue = celix_filter_findAttribute(cFilter.get(), attributeKey.data());
+ return cValue == nullptr ? std::string{} : std::string{cValue};
+ }
+#endif
/**
* @brief Check whether the filter has a attribute with the provided attribute key.
*/
+#if __cplusplus >= 201703L //C++17 or higher
[[nodiscard]] bool hasAttribute(std::string_view attributeKey) const {
return celix_filter_findAttribute(cFilter.get(), attributeKey.data()) != nullptr;
}
+#else
+ bool hasAttribute(const std::string& attributeKey) const {
+ return celix_filter_findAttribute(cFilter.get(), attributeKey.data()) != nullptr;
+ }
+#endif
/**
* @brief Check whether the filter indicates the mandatory presence of an attribute with a specific value for the provided attribute key.
@@ -128,12 +146,18 @@ namespace celix {
* using this method for attribute key "key1" on filter "(key1>=value1)" yields false.
* using this method for attribute key "key1" on filter "(|(key1=value1)(key2=value2))" yields false.
*/
+#if __cplusplus >= 201703L //C++17 or higher
[[nodiscard]] bool hasMandatoryEqualsValueAttribute(std::string_view attributeKey) const {
return celix_filter_hasMandatoryEqualsValueAttribute(cFilter.get(), attributeKey.data());
}
+#else
+ bool hasMandatoryEqualsValueAttribute(const std::string& attributeKey) const {
+ return celix_filter_hasMandatoryEqualsValueAttribute(cFilter.get(), attributeKey.c_str());
+ }
+#endif
/**
- * @brief Chek whether the filter indicates the mandatory absence of an attribute, regardless of its value, for the provided attribute key.
+ * @brief Check whether the filter indicates the mandatory absence of an attribute, regardless of its value, for the provided attribute key.
*
* example:
* using this function for attribute key "key1" on the filter "(!(key1=*))" yields true.
@@ -141,9 +165,15 @@ namespace celix {
* using this function for attribute key "key1" on the filter "(key1=value)" yields false.
* using this function for attribute key "key1" on the filter "(|(!(key1=*))(key2=value2))" yields false.
*/
+#if __cplusplus >= 201703L //C++17 or higher
[[nodiscard]] bool hasMandatoryNegatedPresenceAttribute(std::string_view attributeKey) const {
return celix_filter_hasMandatoryNegatedPresenceAttribute(cFilter.get(), attributeKey.data());
}
+#else
+ bool hasMandatoryNegatedPresenceAttribute(const std::string& attributeKey) const {
+ return celix_filter_hasMandatoryNegatedPresenceAttribute(cFilter.get(), attributeKey.data());
+ }
+#endif
/**
* @brief Get the underlining C filter object.
@@ -163,11 +193,11 @@ namespace celix {
}
private:
- static std::shared_ptr<celix_filter_t> createFilter(std::string_view filterStr) {
- if (filterStr.empty()) {
+ static std::shared_ptr<celix_filter_t> createFilter(const char* filterStr) {
+ if (filterStr == nullptr || strnlen(filterStr, 1) == 0) {
return nullptr;
}
- auto* cf = celix_filter_create(filterStr.data());
+ auto* cf = celix_filter_create(filterStr);
if (cf == nullptr) {
throw celix::FilterException{"Invalid LDAP filter '" + std::string{filterStr} + "'"};
}
diff --git a/libs/utils/include/celix/Properties.h b/libs/utils/include/celix/Properties.h
index 1504dab0..6af04f82 100644
--- a/libs/utils/include/celix/Properties.h
+++ b/libs/utils/include/celix/Properties.h
@@ -296,6 +296,9 @@ namespace celix {
return celix_properties_getAsBool(cProps.get(), key.data(), defaultValue);
}
+ /**
+ * @brief Sets a T&& property. Will use (std::) to_string to convert the value to string.
+ */
template<typename T>
void set(std::string_view key, T&& value) {
if constexpr (std::is_same_v<std::decay_t<T>, bool>) {
@@ -347,13 +350,6 @@ namespace celix {
celix_properties_set(cProps.get(), key.c_str(), value.c_str());
}
- /**
- * @brief Sets a property
- */
- void set(const std::string& key, const char* value) {
- celix_properties_set(cProps.get(), key.c_str(), value);
- }
-
/**
* @brief Sets a bool property
*/
@@ -362,13 +358,22 @@ namespace celix {
}
/**
- * @brief Sets a T property. Will use std::to_string to convert the value to string.
+ * @brief Sets a T property. Will use (std::) to_string to convert the value to string.
*/
template<typename T>
void set(const std::string& key, T value) {
using namespace std;
celix_properties_set(cProps.get(), key.c_str(), to_string(value).c_str());
}
+
+ /**
+ * @brief Sets a const char* property.
+ */
+ template<>
+ void set<const char*>(const std::string& key, const char* value) {
+ using namespace std;
+ celix_properties_set(cProps.get(), key.c_str(), value);
+ }
#endif
/**
diff --git a/libs/utils/include/celix/Utils.h b/libs/utils/include/celix/Utils.h
index 5a72e36a..8eb25f61 100644
--- a/libs/utils/include/celix/Utils.h
+++ b/libs/utils/include/celix/Utils.h
@@ -83,6 +83,27 @@ namespace impl {
}
}
+namespace celix {
+ /**
+ * @brief Splits a string using the provided delim.
+ *
+ * Also trims the entries from whitespaces.
+ * @param str The string to split
+ * @param delimiter The delimiter to use (default ",")
+ */
+ inline std::vector<std::string> split(const std::string& str, const std::string& delimiter = ",") {
+ std::vector<std::string> result{};
+ std::string delimiters = std::string{delimiter} + " \t";
+ size_t found;
+ size_t pos = 0;
+ while ((found = str.find_first_not_of(delimiters, pos)) != std::string::npos) {
+ pos = str.find_first_of(delimiters, found);
+ result.emplace_back(str.substr(found, pos - found));
+ }
+ return result;
+ }
+}
+
#if __cplusplus >= 201703L //C++17 or higher
namespace celix::impl {
@@ -194,25 +215,6 @@ namespace celix {
return "";
}
}
-
- /**
- * @brief Splits a string using the provided delim.
- *
- * Also trims the entries from whitespaces.
- * @param str The string to split
- * @param delimiter The delimiter to use (default ",")
- */
- inline std::vector<std::string> split(std::string_view str, std::string_view delimiter = ",") {
- std::vector<std::string> result{};
- std::string delimiters = std::string{delimiter} + " \t";
- size_t found;
- size_t pos = 0;
- while ((found = str.find_first_not_of(delimiters, pos)) != std::string::npos) {
- pos = str.find_first_of(delimiters, found);
- result.emplace_back(str.substr(found, pos - found));
- }
- return result;
- }
}
#else //Assuming at least C++11