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 2021/10/10 16:48:51 UTC
[celix] 01/01: Updates C++ header only to C++17,
except the for already existing C++ Dep Man headers
This is an automated email from the ASF dual-hosted git repository.
pnoltes pushed a commit to branch feature/cxx17_headers
in repository https://gitbox.apache.org/repos/asf/celix.git
commit a620a2e2864e6414668ffbc2b06fa09097eae65b
Author: Pepijn Noltes <pn...@apache.org>
AuthorDate: Sun Oct 10 18:48:33 2021 +0200
Updates C++ header only to C++17, except the for already existing C++ Dep Man headers
---
CMakeLists.txt | 2 +-
README.md | 2 +-
bundles/CMakeLists.txt | 7 +-
bundles/shell/shell/CMakeLists.txt | 1 -
bundles/shell/shell/src/lb_command.c | 18 +-
cmake/cmake_celix/BundlePackaging.cmake | 19 +-
cmake/cmake_celix/ContainerPackaging.cmake | 2 +-
documents/cmake_commands/README.md | 21 +-
examples/CMakeLists.txt | 2 +-
libs/framework/CMakeLists.txt | 6 +-
libs/framework/gtest/CMakeLists.txt | 38 ++-
.../gtest/src/CxxBundleContextTestSuite.cc | 75 +++++-
.../gtest/src/CxxFrameworkFactoryTestSuite.cc | 1 +
libs/framework/gtest/src/CxxUtilsTestSuite.cc | 62 -----
.../gtest/src/DependencyManagerTestSuite.cc | 46 +++-
libs/framework/gtest/subdir/CMakeLists.txt | 3 +-
.../framework/gtest/subdir/src/{foo.c => sublib.c} | 6 +-
libs/framework/include/bundle.h | 3 +
libs/framework/include/celix/Bundle.h | 75 +++++-
libs/framework/include/celix/BundleActivator.h | 112 ++++-----
libs/framework/include/celix/BundleContext.h | 20 +-
libs/framework/include/celix/Constants.h | 8 +
libs/framework/include/celix/Exception.h | 9 +-
libs/framework/include/celix/Framework.h | 6 +-
libs/framework/include/celix/FrameworkFactory.h | 2 +-
.../include/celix/ServiceRegistrationBuilder.h | 12 +-
libs/framework/include/celix/TrackerBuilders.h | 39 +--
libs/framework/include/celix/Trackers.h | 21 +-
libs/framework/include/celix/UseServiceBuilder.h | 6 +-
libs/framework/include/celix/Utils.h | 122 ---------
libs/framework/include/celix/dm/Component_Impl.h | 12 +-
libs/framework/include/celix_bundle.h | 24 +-
libs/framework/include/celix_bundle_activator.h | 42 +++-
libs/framework/include/celix_bundle_context.h | 280 ++++++++++++---------
libs/framework/include/celix_constants.h | 12 +
libs/framework/include/module.h | 4 +
libs/framework/src/bundle.c | 31 ++-
libs/framework/src/bundle_context.c | 1 +
libs/framework/src/bundle_private.h | 5 +-
.../{celix_library_loader.c => celix_libloader.c} | 25 +-
.../{celix_library_loader.h => celix_libloader.h} | 34 ++-
libs/framework/src/framework.c | 5 +-
libs/framework/src/manifest_parser.c | 36 +--
libs/framework/src/manifest_parser.h | 2 +
libs/framework/src/module.c | 62 +++--
libs/framework/src/service_registry.c | 5 +-
libs/framework/src/service_tracker.c | 22 +-
libs/framework/src/service_tracker_private.h | 2 +
libs/promises/api/celix/impl/SharedPromiseState.h | 4 +-
libs/utils/gtest/CMakeLists.txt | 3 +
.../gtest/src/CxxFilterTestSuite.cc | 4 +-
.../gtest/src/CxxPropertiesTestSuite.cc | 11 +-
libs/utils/gtest/src/CxxUtilsTestSuite.cc | 121 +++++++++
libs/{framework => utils}/include/celix/Filter.h | 36 ++-
.../include/celix/Properties.h | 34 ++-
libs/utils/include/celix/Utils.h | 240 ++++++++++++++++++
56 files changed, 1203 insertions(+), 600 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 88ec2f6..deea4e5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -48,7 +48,7 @@ set(CMAKE_C_FLAGS "-D_GNU_SOURCE -std=gnu99 -fPIC ${CMAKE_C_FLAGS}")
set(CMAKE_C_FLAGS "-Wall -Werror ${CMAKE_C_FLAGS}")
# Set C++ specific flags
-set(CMAKE_CXX_STANDARD 17) #test code and newer C++ bundles can be C++17. The Celix::framework and Celix::CxxShell is still C++11
+set(CMAKE_CXX_STANDARD 17) #Celix header only C++ supported is based on C++17.
set(CMAKE_CXX_FLAGS "-fno-rtti ${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "-Wall -Werror -Wextra -Weffc++ ${CMAKE_CXX_FLAGS}")
diff --git a/README.md b/README.md
index 2480116..546e4c2 100644
--- a/README.md
+++ b/README.md
@@ -22,7 +22,7 @@ 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 the OSGi specification adapted to C and C++ (C++11). It is a framework to develop (dynamic) modular software applications using component and/or service-oriented programming.
+Apache Celix is an implementation of the OSGi specification adapted to C and C++ (C++17). It is a framework to develop (dynamic) modular software applications using component and/or service-oriented programming.
## Documentation
- [Building Apache Celix](documents/building/README.md)
diff --git a/bundles/CMakeLists.txt b/bundles/CMakeLists.txt
index fad202b..d84f4e0 100644
--- a/bundles/CMakeLists.txt
+++ b/bundles/CMakeLists.txt
@@ -15,6 +15,7 @@
# specific language governing permissions and limitations
# under the License.
+# Celix C bundles
add_subdirectory(http_admin)
add_subdirectory(logging)
add_subdirectory(shell)
@@ -22,4 +23,8 @@ add_subdirectory(device_access)
add_subdirectory(deployment_admin)
add_subdirectory(remote_services)
add_subdirectory(pubsub)
-add_subdirectory(cxx_remote_services)
+
+# Celix C++17 bundles
+if (CELIX_CXX)
+ add_subdirectory(cxx_remote_services)
+endif ()
diff --git a/bundles/shell/shell/CMakeLists.txt b/bundles/shell/shell/CMakeLists.txt
index 432a52c..0d8ab19 100644
--- a/bundles/shell/shell/CMakeLists.txt
+++ b/bundles/shell/shell/CMakeLists.txt
@@ -70,7 +70,6 @@ if (SHELL)
add_library(Celix::shell ALIAS shell)
if (CELIX_CXX)
- set(CMAKE_CXX_STANDARD 11) #Note that the Celix::CxxShell uses C++11 only
add_celix_bundle(ShellCxx
SYMBOLIC_NAME "apache::celix::CxxShell"
VERSION "2.1.0"
diff --git a/bundles/shell/shell/src/lb_command.c b/bundles/shell/shell/src/lb_command.c
index 902b67e..73af76d 100644
--- a/bundles/shell/shell/src/lb_command.c
+++ b/bundles/shell/shell/src/lb_command.c
@@ -135,23 +135,7 @@ static void lbCommand_listBundles(celix_bundle_context_t *ctx, const lb_options_
}
if (sub_status == CELIX_SUCCESS) {
- if (id == CELIX_FRAMEWORK_BUNDLE_ID) {
- name_str = "Celix framework";
- } else {
- bundle_archive_t* arch = NULL;
- bundle_revision_t* rev = NULL;
- manifest_pt man = NULL;
- bundle_getArchive(bundle_ptr, &arch);
- if (arch != NULL) {
- bundleArchive_getCurrentRevision(arch, &rev);
- if (rev != NULL) {
- bundleRevision_getManifest(rev, &man);
- if (man != NULL) {
- name_str = manifest_getValue(man, "Bundle-Name");
- }
- }
- }
- }
+ name_str = celix_bundle_getName(bundle_ptr);
}
if (sub_status == CELIX_SUCCESS) {
diff --git a/cmake/cmake_celix/BundlePackaging.cmake b/cmake/cmake_celix/BundlePackaging.cmake
index 57004c8..844625a 100644
--- a/cmake/cmake_celix/BundlePackaging.cmake
+++ b/cmake/cmake_celix/BundlePackaging.cmake
@@ -381,10 +381,27 @@ function(bundle_private_libs)
endfunction()
#[[
-Add libraries to a bundle. The libraries should be cmake library targets or an absolute path to an existing library.
+Add libraries to a bundle. A libraries should be a cmake library target or an absolute path to existing library.
The libraries will be copied into the bundle zip and activator library will be linked (PRIVATE) against them.
+Apache Celix uses dlopen with RTLD_LOCAL to load the activator library in a bundle.
+It is important to note that dlopen will always load the activator library,
+but not always load the libraries the bundle activator library is linked against.
+If the activator library is linked against a library which is already loaded, the already loaded library will be used.
+More specifically dlopen will decide this based on the NEEDED header in the activator library
+and the SO_NAME headers of the already loaded libraries.
+
+For example installing in order:
+ - Bundle A with a private library libfoo (SONAME=libfoo.so) and
+ - Bundle B with a private library libfoo (SONAME=libfoo.so).
+Will result in Bundle B also using libfoo loaded from the cache dir in Bundle A.
+
+This also applies if multiple Celix frameworks are created in the same process. For example installed in order:
+ - Bundle A with a private library libfoo (SONAME=libfoo.so) in Celix Framework A and
+ - The same Bundle A in Celix Framework B.
+Will result in Bundle A from Framework B to use the libfoo loaded from the cache dir of Bundle A in framework A.
+
celix_bundle_private_libs(<bundle_target>
lib1 lib2 ...
)
diff --git a/cmake/cmake_celix/ContainerPackaging.cmake b/cmake/cmake_celix/ContainerPackaging.cmake
index 60c2bd4..83a98c8 100644
--- a/cmake/cmake_celix/ContainerPackaging.cmake
+++ b/cmake/cmake_celix/ContainerPackaging.cmake
@@ -202,7 +202,7 @@ $<$<BOOL:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_LEVEL_2>>:CELIX
$<$<BOOL:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_LEVEL_3>>:CELIX_AUTO_START_3=$<JOIN:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_LEVEL_3>, >\\n>\\
$<$<BOOL:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_LEVEL_4>>:CELIX_AUTO_START_4=$<JOIN:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_LEVEL_4>, >\\n>\\
$<$<BOOL:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_LEVEL_5>>:CELIX_AUTO_START_5=$<JOIN:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_LEVEL_5>, >\\n>\\
-$<$<BOOL:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_LEVEL_6>>:CELIX_AUTO_START_6=$<JOIN:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_LEVEL_6>, >\\n>\\
+$<$<BOOL:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_LEVEL_6>>:CELIX_AUTO_START_5=$<JOIN:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_LEVEL_6>, >\\n>\\
$<JOIN:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_EMBEDDED_PROPERTIES>,\\n\\
>\";
diff --git a/documents/cmake_commands/README.md b/documents/cmake_commands/README.md
index 6f9a398..d6f79dd 100644
--- a/documents/cmake_commands/README.md
+++ b/documents/cmake_commands/README.md
@@ -87,7 +87,26 @@ add_celix_bundle(<bundle_target_name>
## celix_bundle_private_libs
Add libraries to a bundle. The libraries should be cmake library targets or an absolute path to an existing library.
-The libraries will be copied into the bundle zip and activator library will be linked (PRIVATE) against them.
+The libraries will be copied into the bundle zip and activator library will be linked (PRIVATE) against them.
+
+Apache Celix uses dlopen with RTLD_LOCAL to load the activator library in a bundle.
+It is important to note that dlopen will always load the activator library,
+but not always load the libraries the bundle activator library is linked against.
+If the activator library is linked against a library which is already loaded, the already loaded library will be used.
+More specifically dlopen will decide this based on the NEEDED header in the activator library
+and the SO_NAME headers of the already loaded libraries.
+
+For example installing in order:
+- Bundle A with a private library libfoo (SONAME=libfoo.so) and
+- Bundle B with a private library libfoo (SONAME=libfoo.so).
+ Will result in Bundle B also using libfoo loaded from the cache dir in Bundle A.
+
+This also applies if multiple Celix frameworks are created in the same process. For example installed in order:
+- Bundle A with a private library libfoo (SONAME=libfoo.so) in Celix Framework A and
+- The same Bundle A in Celix Framework B.
+ Will result in Bundle A from Framework B to use the libfoo loaded from the cache dir of Bundle A in framework A.
+
+Will result in BundleA from framework B to use the libfoo loaded in BundleA from framework A.
```CMake
celix_bundle_private_libs(<bundle_target>
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 80b88e7..316720b 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -30,6 +30,6 @@
cmake_minimum_required (VERSION 3.4)
project (CelixUse C CXX)
set(CMAKE_C_FLAGS "-D_GNU_SOURCE -std=gnu99 ${CMAKE_C_FLAGS}")
-set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD 17)
find_package(Celix REQUIRED)
add_subdirectory(celix-examples examples)
diff --git a/libs/framework/CMakeLists.txt b/libs/framework/CMakeLists.txt
index cfc1d22..f0bcb10 100644
--- a/libs/framework/CMakeLists.txt
+++ b/libs/framework/CMakeLists.txt
@@ -19,8 +19,6 @@ find_package(ZLIB REQUIRED)
find_package(UUID REQUIRED)
find_package(CURL REQUIRED)
-set(CMAKE_CXX_STANDARD 11) #Note that the Celix framework C++ (header only) library uses C++11 only
-
set(SOURCES
src/attribute.c src/bundle.c src/bundle_archive.c src/bundle_cache.c
src/bundle_context.c src/bundle_revision.c src/capability.c src/celix_errorcodes.c
@@ -32,10 +30,10 @@ set(SOURCES
src/celix_log.c src/celix_launcher.c
src/celix_framework_factory.c
src/dm_dependency_manager_impl.c src/dm_component_impl.c
- src/dm_service_dependency.c src/celix_library_loader.c
+ src/dm_service_dependency.c src/celix_libloader.c
src/framework_bundle_lifecycle_handler.c
src/celix_bundle_state.c
-)
+ )
add_library(framework SHARED ${SOURCES})
set_target_properties(framework PROPERTIES OUTPUT_NAME "celix_framework")
target_include_directories(framework PUBLIC
diff --git a/libs/framework/gtest/CMakeLists.txt b/libs/framework/gtest/CMakeLists.txt
index 9880463..1f6d2e9 100644
--- a/libs/framework/gtest/CMakeLists.txt
+++ b/libs/framework/gtest/CMakeLists.txt
@@ -16,6 +16,10 @@
# under the License.
add_celix_bundle(simple_test_bundle1 NO_ACTIVATOR VERSION 1.0.0)
+celix_bundle_name(simple_test_bundle1 "Simple Test Bundle")
+celix_bundle_group(simple_test_bundle1 "test/group")
+celix_bundle_description(simple_test_bundle1 "Test Description")
+
add_celix_bundle(simple_test_bundle2 NO_ACTIVATOR VERSION 1.0.0)
add_celix_bundle(simple_test_bundle3 NO_ACTIVATOR VERSION 1.0.0)
add_celix_bundle(bundle_with_exception SOURCES src/nop_activator.c VERSION 1.0.0)
@@ -34,22 +38,20 @@ endif()
add_dependencies(unresolveable_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/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/CxxPropertiesTestSuite.cc
src/HelloWorldCxxActivator.cc
- src/CxxFilterTestSuite.cc
src/CxxFrameworkFactoryTestSuite.cc
- src/CxxBundleActivatorTestSuite.cc
- src/CxxUtilsTestSuite.cc
-)
-
-target_link_libraries(test_framework Celix::framework CURL::libcurl GTest::gtest GTest::gtest_main)
-add_dependencies(test_framework simple_test_bundle1_bundle simple_test_bundle2_bundle simple_test_bundle3_bundle simple_test_bundle4_bundle simple_test_bundle5_bundle bundle_with_exception_bundle unresolveable_bundle_bundle simple_cxx_bundle)
+ src/CxxBundleActivatorTestSuite.cc)
+target_link_libraries(test_framework PRIVATE Celix::framework CURL::libcurl GTest::gtest GTest::gtest_main)
+add_celix_bundle_dependencies(test_framework
+ simple_test_bundle1
+ simple_test_bundle2 simple_test_bundle3 simple_test_bundle4
+ simple_test_bundle5 bundle_with_exception unresolveable_bundle simple_cxx)
target_include_directories(test_framework PRIVATE ../src)
celix_get_bundle_file(simple_cxx_bundle SIMPLE_CXX_BUNDLE_LOC)
@@ -73,3 +75,13 @@ configure_file(framework2.properties.in framework2.properties @ONLY)
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)
+setup_target_for_coverage(test_dep_man_with_cxx11 SCAN_DIR ..)
+
+
diff --git a/libs/framework/gtest/src/CxxBundleContextTestSuite.cc b/libs/framework/gtest/src/CxxBundleContextTestSuite.cc
index d6ebe44..02f5263 100644
--- a/libs/framework/gtest/src/CxxBundleContextTestSuite.cc
+++ b/libs/framework/gtest/src/CxxBundleContextTestSuite.cc
@@ -158,7 +158,7 @@ TEST_F(CxxBundleContextTestSuite, UseServicesTest) {
TEST_F(CxxBundleContextTestSuite, UseServicesWithFilterTest) {
auto svc = std::make_shared<CInterface>(CInterface{nullptr, nullptr});
auto svcReg1 = ctx->registerService<CInterface>(svc).build();
- auto svcReg2 = ctx->registerService<CInterface>(svc).addProperty("key", "val1").build();
+ auto svcReg2 = ctx->registerService<CInterface>(svc).setProperties(celix::Properties{{"key", "val1"}}).build();
auto svcReg3 = ctx->registerService<CInterface>(svc).addProperty("key", "val2").build();
EXPECT_EQ(3, ctx->useServices<CInterface>().build());
@@ -169,7 +169,7 @@ TEST_F(CxxBundleContextTestSuite, UseServicesWithFilterTest) {
celix::Filter f{"(key=val2)"};
EXPECT_EQ(1, ctx->useServices<CInterface>().setFilter(f).build());
- EXPECT_THROW(ctx->useServices<CInterface>().setFilter(celix::Filter{"bla"}).build(), celix::Exception);
+ EXPECT_THROW(ctx->useServices<CInterface>().setFilter(celix::Filter{"bla"}).build(), celix::FilterException);
}
@@ -325,6 +325,7 @@ TEST_F(CxxBundleContextTestSuite, TrackBundlesTest) {
};
auto tracker = ctx->trackBundles()
+ .includeFrameworkBundleInCallback()
.addOnInstallCallback(cb)
.addOnStartCallback(cb)
.addOnStopCallback(cb)
@@ -332,28 +333,30 @@ TEST_F(CxxBundleContextTestSuite, TrackBundlesTest) {
tracker->wait();
EXPECT_EQ(celix::TrackerState::OPEN, tracker->getState());
EXPECT_TRUE(tracker->isOpen());
- EXPECT_EQ(0, count.load());
+ EXPECT_EQ(2, count.load()); //count 1x install, 1x start is from the framework bundle
long bndId = ctx->installBundle("non-existing");
EXPECT_EQ(-1, bndId); //not installed
+ EXPECT_EQ(2, count.load());
long bndId1 = ctx->installBundle(TEST_BND1_LOC);
EXPECT_GE(bndId1, 0);
- EXPECT_EQ(2, count.load()); // 1x install, 1x start
+ EXPECT_EQ(4, count.load()); // 2x install, 2x start
long bndId2 = ctx->installBundle(TEST_BND2_LOC, false);
EXPECT_GE(bndId1, 0);
- EXPECT_EQ(3, count.load()); // 2x install, 1x start
+ EXPECT_EQ(5, count.load()); // 3x install, 2x start
ctx->startBundle(bndId2);
- EXPECT_EQ(4, count.load()); // 2x install, 2x start
+ EXPECT_EQ(6, count.load()); // 3x install, 3x start
+ count = 0;
ctx->uninstallBundle(bndId1);
- EXPECT_EQ(5, count.load()); // 2x install, 2x start, 1x stop
+ EXPECT_EQ(1, count.load()); // 1x stop
ctx->stopBundle(bndId2);
- EXPECT_EQ(6, count.load()); // 2x install, 2x start, 2x stop
+ EXPECT_EQ(2, count.load()); // 2x stop
ctx->startBundle(bndId2);
- EXPECT_EQ(7, count.load()); // 2x install, 3x start, 2x stop
+ EXPECT_EQ(3, count.load()); // 1x start, 2x stop
}
TEST_F(CxxBundleContextTestSuite, OnRegisterAndUnregisterCallbacks) {
@@ -438,6 +441,7 @@ TEST_F(CxxBundleContextTestSuite, TrackServices) {
auto metaTracker = ctx->trackServiceTrackers<TestInterface>()
.addOnTrackerCreatedCallback([&count](const celix::ServiceTrackerInfo& info) {
+ EXPECT_GE(info.trackerOwnerBundleId, 0);
EXPECT_EQ(celix::typeName<TestInterface>(), info.serviceName);
count++;
})
@@ -581,9 +585,18 @@ TEST_F(CxxBundleContextTestSuite, setServicesWithTrackerWhenMultipleRegistration
}
count++;
})
+ .addSetWithOwner([&count](std::shared_ptr<TestInterface> /*svc*/, const std::shared_ptr<const celix::Properties>& props, const std::shared_ptr<const celix::Bundle>& bnd) {
+ if (props) {
+ std::cout << "Setting svc with svc id " << props->getAsLong(celix::SERVICE_ID, -1) << std::endl;
+ std::cout << "from bnd " << std::to_string(bnd->getId());
+ } else {
+ std::cout << "Unsetting svc" << std::endl;
+ }
+ count++;
+ })
.build();
tracker->wait();
- EXPECT_EQ(1, count.load()); //NOTE ensure that the service tracker only calls set once for opening tracker even if 3 service exists.
+ EXPECT_EQ(2, count.load()); //NOTE ensure that the service tracker only calls set once for opening tracker even if 3 service exists.
count = 0;
tracker->close();
@@ -591,7 +604,7 @@ TEST_F(CxxBundleContextTestSuite, setServicesWithTrackerWhenMultipleRegistration
//TODO improve this. For now closing a tracker will inject other service before getting to nullptr.
//Also look into why this is not happening in the C service tracker test.
- EXPECT_EQ(3, count.load());
+ EXPECT_EQ(6, count.load());
}
TEST_F(CxxBundleContextTestSuite, WaitForAllEvents) {
@@ -653,4 +666,42 @@ TEST_F(CxxBundleContextTestSuite, CheckStandardServiceProperties) {
EXPECT_TRUE(called);
celix_bundleContext_unregisterService(ctx->getCBundleContext(), svcId);
-}
\ No newline at end of file
+}
+
+TEST_F(CxxBundleContextTestSuite, GetBundleInformation) {
+
+ EXPECT_EQ(ctx->getBundle().getSymbolicName(), std::string{"celix_framework"});
+ EXPECT_EQ(ctx->getBundle().getName(), std::string{"Celix Framework"});
+ EXPECT_EQ(ctx->getBundle().getGroup(), std::string{"Celix/Framework"});
+ EXPECT_EQ(ctx->getBundle().getDescription(), std::string{"The Celix Framework System Bundle"});
+
+ std::atomic<bool> startCalled{false};
+ auto bndTracker = ctx->trackBundles()
+ .addOnStartCallback([&startCalled](const celix::Bundle& bnd) {
+ EXPECT_EQ(bnd.getSymbolicName(), std::string{"simple_test_bundle1"});
+ EXPECT_EQ(bnd.getName(), std::string{"Simple Test Bundle"});
+ EXPECT_EQ(bnd.getGroup(), std::string{"test/group"});
+ EXPECT_EQ(bnd.getDescription(), std::string{"Test Description"});
+ startCalled = true;
+ })
+ .build();
+
+ long bndId1 = ctx->installBundle(TEST_BND1_LOC);
+ EXPECT_GE(bndId1, 0);
+ ctx->waitForEvents();
+ EXPECT_TRUE(startCalled);
+}
+
+class TestInterfaceWithStaticInfo {
+public:
+ static constexpr std::string_view NAME = "TestName";
+ static constexpr std::string_view VERSION = "1.2.3";
+};
+
+TEST_F(CxxBundleContextTestSuite, RegisterServiceWithNameAndVersionInfo) {
+
+ auto reg = ctx->registerService<TestInterfaceWithStaticInfo>(std::make_shared<TestInterfaceWithStaticInfo>())
+ .build();
+ EXPECT_EQ(reg->getServiceName(), "TestName");
+ EXPECT_EQ(reg->getServiceVersion(), "1.2.3");
+}
diff --git a/libs/framework/gtest/src/CxxFrameworkFactoryTestSuite.cc b/libs/framework/gtest/src/CxxFrameworkFactoryTestSuite.cc
index 8e1a62a..04ce44c 100644
--- a/libs/framework/gtest/src/CxxFrameworkFactoryTestSuite.cc
+++ b/libs/framework/gtest/src/CxxFrameworkFactoryTestSuite.cc
@@ -31,6 +31,7 @@ public:
TEST_F(CxxFrameworkFactoryTestSuite, CreateDestroy) {
auto fw = celix::createFramework();
+ EXPECT_TRUE(fw->getFrameworkBundleContext()->getBundle().isSystemBundle());
}
TEST_F(CxxFrameworkFactoryTestSuite, WaitForStop) {
diff --git a/libs/framework/gtest/src/CxxUtilsTestSuite.cc b/libs/framework/gtest/src/CxxUtilsTestSuite.cc
deleted file mode 100644
index 28d8594..0000000
--- a/libs/framework/gtest/src/CxxUtilsTestSuite.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include <gtest/gtest.h>
-
-#include "celix/Utils.h"
-
-class CxxUtilsTestSuite : public ::testing::Test {
-public:
-};
-
-namespace example {
- class TestType {
-
- };
-}
-
-
-TEST_F(CxxUtilsTestSuite, TypenameTest) {
- auto name = celix::typeName<example::TestType>();
- EXPECT_FALSE(name.empty());
-}
-
-TEST_F(CxxUtilsTestSuite, SplitTest) {
- auto tokens = celix::split("item1,item2,item3");
- ASSERT_EQ(tokens.size(), 3);
- EXPECT_EQ(tokens[0], "item1");
- EXPECT_EQ(tokens[1], "item2");
- EXPECT_EQ(tokens[2], "item3");
-
- tokens = celix::split(" item1 , item2 , item3 ");
- ASSERT_EQ(tokens.size(), 3);
- EXPECT_EQ(tokens[0], "item1");
- EXPECT_EQ(tokens[1], "item2");
- EXPECT_EQ(tokens[2], "item3");
-
- tokens = celix::split(" item1 , ");
- ASSERT_EQ(tokens.size(), 1);
- EXPECT_EQ(tokens[0], "item1");
-
- tokens = celix::split("");
- EXPECT_EQ(tokens.size(), 0);
-
- tokens = celix::split(" , , ");
- EXPECT_EQ(tokens.size(), 0);
-}
\ No newline at end of file
diff --git a/libs/framework/gtest/src/DependencyManagerTestSuite.cc b/libs/framework/gtest/src/DependencyManagerTestSuite.cc
index 672a2f4..8737fcd 100644
--- a/libs/framework/gtest/src/DependencyManagerTestSuite.cc
+++ b/libs/framework/gtest/src/DependencyManagerTestSuite.cc
@@ -197,7 +197,7 @@ TEST_F(DependencyManagerTestSuite, CxxDmGetInfo) {
auto info = mng.getInfo();
EXPECT_EQ(info.bndId, 0);
- EXPECT_EQ(info.bndSymbolicName, "Framework");
+ EXPECT_EQ(info.bndSymbolicName, "celix_framework");
EXPECT_EQ(info.components.size(), 0); //not build yet
mng.build();
@@ -773,4 +773,46 @@ TEST_F(DependencyManagerTestSuite, ComponentContextShouldNotLeak) {
.addContext(std::make_shared<std::vector<std::string>>())
.build();
//note should not leak mem
-}
\ No newline at end of file
+}
+
+#if __cplusplus >= 201703L //C++17 or higher
+
+class TestInterfaceWithStaticInfo {
+public:
+ static constexpr const char * const NAME = "TestName";
+ static constexpr const char * const VERSION = "1.2.3";
+};
+
+TEST_F(DependencyManagerTestSuite, ProvideInterfaceWithStaticInfo) {
+ class TestComponent : public TestInterfaceWithStaticInfo {};
+ celix::dm::DependencyManager dm{ctx};
+ auto& cmp = dm.createComponent<TestComponent>();
+ cmp.createProvidedService<TestInterfaceWithStaticInfo>();
+ cmp.build();
+ EXPECT_EQ(cmp.getState(), celix::dm::ComponentState::TRACKING_OPTIONAL);
+
+ auto info = dm.getInfo();
+ EXPECT_EQ(info.components[0].interfacesInfo[0].serviceName, "TestName");
+ auto& props = info.components[0].interfacesInfo[0].properties;
+ const auto it = props.find(celix::SERVICE_VERSION);
+ ASSERT_TRUE(it != props.end());
+ EXPECT_EQ(it->second, "1.2.3");
+}
+
+TEST_F(DependencyManagerTestSuite, CreateInterfaceWithStaticInfo) {
+ class TestComponent : public TestInterfaceWithStaticInfo {};
+ celix::dm::DependencyManager dm{ctx};
+ auto& cmp = dm.createComponent<TestComponent>();
+ cmp.addInterface<TestInterfaceWithStaticInfo>();
+ cmp.build();
+ EXPECT_EQ(cmp.getState(), celix::dm::ComponentState::TRACKING_OPTIONAL);
+
+ auto info = dm.getInfo();
+ EXPECT_EQ(info.components[0].interfacesInfo[0].serviceName, "TestName");
+ auto& props = info.components[0].interfacesInfo[0].properties;
+ const auto it = props.find(celix::SERVICE_VERSION);
+ ASSERT_TRUE(it != props.end());
+ EXPECT_EQ(it->second, "1.2.3");
+}
+
+#endif
\ No newline at end of file
diff --git a/libs/framework/gtest/subdir/CMakeLists.txt b/libs/framework/gtest/subdir/CMakeLists.txt
index 4956e3e..780305c 100644
--- a/libs/framework/gtest/subdir/CMakeLists.txt
+++ b/libs/framework/gtest/subdir/CMakeLists.txt
@@ -18,4 +18,5 @@
add_celix_bundle(simple_test_bundle4 NO_ACTIVATOR VERSION 1.0.0)
add_celix_bundle(simple_test_bundle5 NO_ACTIVATOR VERSION 1.0.0)
-add_library(sublib SHARED src/foo.c)
+add_library(sublib SHARED src/sublib.c)
+target_link_libraries(sublib PRIVATE Celix::framework)
diff --git a/libs/framework/gtest/subdir/src/foo.c b/libs/framework/gtest/subdir/src/sublib.c
similarity index 94%
rename from libs/framework/gtest/subdir/src/foo.c
rename to libs/framework/gtest/subdir/src/sublib.c
index 6f56eb7..d218f84 100644
--- a/libs/framework/gtest/subdir/src/foo.c
+++ b/libs/framework/gtest/subdir/src/sublib.c
@@ -19,8 +19,10 @@
#include <stdio.h>
-void foo(void);
+void foo();
+char* get_bundle_name();
-void foo(void) {
+void foo() {
printf("nop\n");
}
+
diff --git a/libs/framework/include/bundle.h b/libs/framework/include/bundle.h
index 3ca545e..5cf8998 100644
--- a/libs/framework/include/bundle.h
+++ b/libs/framework/include/bundle.h
@@ -40,6 +40,9 @@ extern "C" {
struct celix_bundle_activator;
typedef struct celix_bundle_activator celix_bundle_activator_t;
+/**
+ * @brief Create system bundle
+ */
FRAMEWORK_EXPORT celix_status_t bundle_create(celix_bundle_t **bundle);
FRAMEWORK_EXPORT celix_status_t
diff --git a/libs/framework/include/celix/Bundle.h b/libs/framework/include/celix/Bundle.h
index a098b3c..9095842 100644
--- a/libs/framework/include/celix/Bundle.h
+++ b/libs/framework/include/celix/Bundle.h
@@ -25,6 +25,16 @@
namespace celix {
+ enum class BundleState {
+ UNKNOWN,
+ UNINSTALLED,
+ INSTALLED,
+ RESOLVED,
+ STARTING,
+ STOPPING,
+ ACTIVE,
+ };
+
/**
* @brief An installed bundle in the Celix framework.
*
@@ -35,20 +45,20 @@ namespace celix {
*/
class Bundle {
public:
- explicit Bundle(celix_bundle_t* _cBnd) : cBnd{_cBnd, [](celix_bundle_t*){/*nop*/}}{}
+ explicit Bundle(celix_bundle_t* _cBnd) : cBnd{_cBnd, [](celix_bundle_t*){/*nop*/}} {}
/**
* @brief get the bundle id.
* @return
*/
- long getId() const { return celix_bundle_getId(cBnd.get()); }
+ [[nodiscard]] long getId() const { return celix_bundle_getId(cBnd.get()); }
/**
* @brief Get the absolute path for a entry path relative in the bundle cache.
* @return The absolute entry path or an empty string if the bundle does not have the entry for the given
* relative path.
*/
- std::string getEntry(const std::string& path) const {
+ [[nodiscard]] std::string getEntry(const std::string& path) const {
std::string result{};
char* entry = celix_bundle_getEntry(cBnd.get(), path.c_str());
if (entry != nullptr) {
@@ -57,6 +67,65 @@ namespace celix {
}
return result;
}
+
+ /**
+ * @brief the symbolic name of the bundle.
+ */
+ [[nodiscard]] std::string getSymbolicName() const {
+ return std::string{celix_bundle_getSymbolicName(cBnd.get())};
+ }
+
+ /**
+ * @brief The name of the bundle.
+ */
+ [[nodiscard]] std::string getName() const {
+ return std::string{celix_bundle_getName(cBnd.get())};
+ }
+
+ /**
+ * @brief The group of the bundle.
+ */
+ [[nodiscard]] std::string getGroup() const {
+ return std::string{celix_bundle_getGroup(cBnd.get())};
+ }
+
+ /**
+ * @brief The descriptoin of the bundle.
+ */
+ [[nodiscard]] std::string getDescription() const {
+ return std::string{celix_bundle_getDescription(cBnd.get())};
+ }
+
+ /**
+ * @brief The current bundle state.
+ */
+ [[nodiscard]] celix::BundleState getState() const {
+ auto cState = celix_bundle_getState(cBnd.get());
+ switch (cState) {
+ case OSGI_FRAMEWORK_BUNDLE_UNINSTALLED:
+ return BundleState::UNINSTALLED;
+ case OSGI_FRAMEWORK_BUNDLE_INSTALLED:
+ return BundleState::INSTALLED;
+ case OSGI_FRAMEWORK_BUNDLE_RESOLVED:
+ return BundleState::RESOLVED;
+ case OSGI_FRAMEWORK_BUNDLE_STARTING:
+ return BundleState::STARTING;
+ case OSGI_FRAMEWORK_BUNDLE_STOPPING:
+ return BundleState::STOPPING;
+ case OSGI_FRAMEWORK_BUNDLE_ACTIVE:
+ return BundleState::ACTIVE;
+ default:
+ return BundleState::UNKNOWN;
+ }
+ }
+
+ /**
+ * @brief whether the bundle is the system (framework) bundle
+ * @return
+ */
+ [[nodiscard]] bool isSystemBundle() const {
+ return celix_bundle_isSystemBundle(cBnd.get());
+ }
private:
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 ecec6f6..ec7a046 100644
--- a/libs/framework/include/celix/BundleActivator.h
+++ b/libs/framework/include/celix/BundleActivator.h
@@ -25,73 +25,71 @@
#include "celix_bundle_activator.h"
#include "celix/BundleContext.h"
-namespace celix {
- namespace impl {
+namespace celix::impl {
- template<typename I>
- struct BundleActivatorData {
- long bndId;
- std::shared_ptr<celix::BundleContext> ctx;
- std::unique_ptr<I> bundleActivator;
- };
+ template<typename I>
+ struct BundleActivatorData {
+ long bndId{};
+ std::shared_ptr<celix::BundleContext> ctx;
+ std::unique_ptr<I> bundleActivator;
+ };
- template<typename I>
- typename std::enable_if<std::is_constructible<I, std::shared_ptr<celix::BundleContext>>::value, celix_status_t>::type
- createActivator(celix_bundle_context_t *cCtx, void **out) {
- auto ctx = std::make_shared<celix::BundleContext>(cCtx);
- auto act = std::unique_ptr<I>(new I{ctx});
- auto *data = new BundleActivatorData<I>{ctx->getBundleId(), std::move(ctx), std::move(act)};
- *out = (void *) data;
- return CELIX_SUCCESS;
- }
+ template<typename I>
+ typename std::enable_if<std::is_constructible<I, std::shared_ptr<celix::BundleContext>>::value, celix_status_t>::type
+ createActivator(celix_bundle_context_t *cCtx, void **out) {
+ auto ctx = std::make_shared<celix::BundleContext>(cCtx);
+ auto act = std::unique_ptr<I>(new I{ctx});
+ auto *data = new BundleActivatorData<I>{ctx->getBundleId(), std::move(ctx), std::move(act)};
+ *out = (void *) data;
+ return CELIX_SUCCESS;
+ }
- template<typename I>
- typename std::enable_if<std::is_constructible<I, std::shared_ptr<celix::dm::DependencyManager>>::value, celix_status_t>::type
- createActivator(celix_bundle_context_t *cCtx, void **out) {
- auto ctx = std::make_shared<celix::BundleContext>(cCtx);
- auto dm = ctx->getDependencyManager();
- auto act = std::unique_ptr<I>(new I{dm});
- dm->start();
- auto *data = new BundleActivatorData<I>{ctx->getBundleId(), std::move(ctx), std::move(act)};
- *out = (void *) data;
- return CELIX_SUCCESS;
- }
+ template<typename I>
+ typename std::enable_if<std::is_constructible<I, std::shared_ptr<celix::dm::DependencyManager>>::value, celix_status_t>::type
+ createActivator(celix_bundle_context_t *cCtx, void **out) {
+ auto ctx = std::make_shared<celix::BundleContext>(cCtx);
+ auto dm = ctx->getDependencyManager();
+ auto act = std::unique_ptr<I>(new I{dm});
+ dm->start();
+ auto *data = new BundleActivatorData<I>{ctx->getBundleId(), std::move(ctx), std::move(act)};
+ *out = (void *) data;
+ return CELIX_SUCCESS;
+ }
- template<typename T>
- void waitForExpired(long bndId, std::weak_ptr<celix::BundleContext>& weakCtx, const char* name, std::weak_ptr<T>& observe) {
- auto start = std::chrono::system_clock::now();
- while (!observe.expired()) {
- auto now = std::chrono::system_clock::now();
- auto durationInSec = std::chrono::duration_cast<std::chrono::seconds>(now - start);
- if (durationInSec > std::chrono::seconds{5}) {
- auto msg = std::string{"Cannot destroy bundle "} + std::to_string(bndId) + ". " + name + " is still in use. std::shared_ptr use count is " + std::to_string(observe.use_count()) + "\n";
- auto ctx = weakCtx.lock();
- if (ctx) {
- ctx->logWarn(msg.c_str());
- } else {
- std::cout << msg;
- }
- start = now;
+ template<typename T>
+ void waitForExpired(long bndId, std::weak_ptr<celix::BundleContext>& weakCtx, const char* name, std::weak_ptr<T>& observe) {
+ auto start = std::chrono::system_clock::now();
+ while (!observe.expired()) {
+ auto now = std::chrono::system_clock::now();
+ auto durationInSec = std::chrono::duration_cast<std::chrono::seconds>(now - start);
+ if (durationInSec > std::chrono::seconds{5}) {
+ auto msg = std::string{"Cannot destroy bundle "} + std::to_string(bndId) + ". " + name + " is still in use. std::shared_ptr use count is " + std::to_string(observe.use_count()) + "\n";
+ auto ctx = weakCtx.lock();
+ if (ctx) {
+ ctx->logWarn(msg.c_str());
+ } else {
+ std::cout << msg;
}
- std::this_thread::sleep_for(std::chrono::milliseconds{50});
+ start = now;
}
+ std::this_thread::sleep_for(std::chrono::milliseconds{50});
}
+ }
- template<typename I>
- celix_status_t destroyActivator(void *userData) {
- auto *data = static_cast<BundleActivatorData<I> *>(userData);
- data->bundleActivator.reset();
- data->ctx->getDependencyManager()->clear();
+ template<typename I>
+ celix_status_t destroyActivator(void *userData) {
+ auto *data = static_cast<BundleActivatorData<I> *>(userData);
+ data->bundleActivator.reset();
+ data->ctx->getDependencyManager()->clear();
- auto bndId = data->bndId;
- std::weak_ptr<celix::BundleContext> ctx = data->ctx;
- std::weak_ptr<celix::dm::DependencyManager> dm = data->ctx->getDependencyManager();
- delete data;
- waitForExpired(bndId, ctx, "celix::BundleContext", ctx);
- waitForExpired(bndId, ctx, "celix::dm::DependencyManager", dm);
- return CELIX_SUCCESS;
- }
+ auto bndId = data->bndId;
+ std::weak_ptr<celix::BundleContext> ctx = data->ctx;
+ std::weak_ptr<celix::dm::DependencyManager> dm = data->ctx->getDependencyManager();
+ delete data;
+ waitForExpired(bndId, ctx, "celix::BundleContext", ctx);
+ waitForExpired(bndId, ctx, "celix::dm::DependencyManager", dm);
+ return CELIX_SUCCESS;
}
}
diff --git a/libs/framework/include/celix/BundleContext.h b/libs/framework/include/celix/BundleContext.h
index 75e5510..66c79a0 100644
--- a/libs/framework/include/celix/BundleContext.h
+++ b/libs/framework/include/celix/BundleContext.h
@@ -377,7 +377,7 @@ namespace celix {
* @brief List the installed and started bundle ids.
* The bundle ids does not include the framework bundle (bundle id celix::FRAMEWORK_BUNDLE_ID).
*/
- std::vector<long> listBundleIds() const {
+ [[nodiscard]] std::vector<long> listBundleIds() const {
std::vector<long> result{};
auto* ids = celix_bundleContext_listBundles(cCtx.get());
result.reserve(celix_arrayList_size(ids));
@@ -399,7 +399,7 @@ 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.
*/
- std::string getConfigProperty(const std::string& name, const std::string& defaultValue) const {
+ [[nodiscard]] 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())};
}
@@ -415,7 +415,7 @@ 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.
*/
- long getConfigPropertyAsLong(const std::string& name, long defaultValue) const {
+ [[nodiscard]] long getConfigPropertyAsLong(const std::string& name, long defaultValue) const {
return celix_bundleContext_getPropertyAsLong(cCtx.get(), name.c_str(), defaultValue);
}
@@ -431,7 +431,7 @@ 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.
*/
- double getConfigPropertyAsDouble(const std::string& name, double defaultValue) const {
+ [[nodiscard]] double getConfigPropertyAsDouble(const std::string& name, double defaultValue) const {
return celix_bundleContext_getPropertyAsDouble(cCtx.get(), name.c_str(), defaultValue);
}
@@ -449,28 +449,28 @@ 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.
*/
- long getConfigPropertyAsBool(const std::string& name, bool defaultValue) const {
+ [[nodiscard]] long getConfigPropertyAsBool(const std::string& name, bool defaultValue) const {
return celix_bundleContext_getPropertyAsBool(cCtx.get(), name.c_str(), defaultValue);
}
/**
* @brief Get the bundle of this bundle context.
*/
- const Bundle& getBundle() const {
+ [[nodiscard]] const Bundle& getBundle() const {
return bnd;
}
/**
* @brief Get the bundle id for the bundle of this bundle context
*/
- long getBundleId() const {
+ [[nodiscard]] long getBundleId() const {
return bnd.getId();
}
/**
* @brief Get the Celix framework for this bundle context.
*/
- std::shared_ptr<Framework> getFramework() const {
+ [[nodiscard]] std::shared_ptr<Framework> getFramework() const {
auto* cFw = celix_bundleContext_getFramework(cCtx.get());
auto fwCtx = std::make_shared<celix::BundleContext>(celix_framework_getFrameworkContext(cFw));
return std::make_shared<Framework>(fwCtx, cFw);
@@ -479,7 +479,7 @@ namespace celix {
/**
* @brief Get the Celix dependency manager for this bundle context
*/
- std::shared_ptr<dm::DependencyManager> getDependencyManager() const {
+ [[nodiscard]] std::shared_ptr<dm::DependencyManager> getDependencyManager() const {
return dm;
}
@@ -489,7 +489,7 @@ namespace celix {
* @warning Try not the depend on the C API from a C++ bundle. If features are missing these should be added to
* the C++ API.
*/
- celix_bundle_context_t* getCBundleContext() const {
+ [[nodiscard]] celix_bundle_context_t* getCBundleContext() const {
return cCtx.get();
}
diff --git a/libs/framework/include/celix/Constants.h b/libs/framework/include/celix/Constants.h
index 8f84ccb..26c4d07 100644
--- a/libs/framework/include/celix/Constants.h
+++ b/libs/framework/include/celix/Constants.h
@@ -211,4 +211,12 @@ namespace celix {
* If not specified ".cache" is used.
*/
constexpr const char * const FRAMEWORK_CACHE_DIR = CELIX_FRAMEWORK_FRAMEWORK_STORAGE;
+
+ /**
+ * @brief Celix framework environment property (named "CELIX_FRAMEWORK_WARN_FOR_MISSING_SERVICE_VERSION")
+ * which configures the Celix framework to print warning when service are registered without a version property.
+ *
+ * Default is true.
+ */
+ constexpr const char * const WARN_FOR_MISSING_SERVICE_VERSION = CELIX_FRAMEWORK_WARN_FOR_MISSING_SERVICE_VERSION;
}
\ No newline at end of file
diff --git a/libs/framework/include/celix/Exception.h b/libs/framework/include/celix/Exception.h
index 5f374d7..27aca02 100644
--- a/libs/framework/include/celix/Exception.h
+++ b/libs/framework/include/celix/Exception.h
@@ -11,11 +11,16 @@ namespace celix {
public:
explicit Exception(std::string msg) : w{std::move(msg)} {}
- const char* what() const noexcept override {
+ Exception(const Exception&) = default;
+ Exception(Exception&&) = default;
+ Exception& operator=(const Exception&) = default;
+ Exception& operator=(Exception&&) = default;
+
+ [[nodiscard]] const char* what() const noexcept override {
return w.c_str();
}
private:
- const std::string w;
+ std::string w;
};
}
diff --git a/libs/framework/include/celix/Framework.h b/libs/framework/include/celix/Framework.h
index e557e55..f679722 100644
--- a/libs/framework/include/celix/Framework.h
+++ b/libs/framework/include/celix/Framework.h
@@ -44,14 +44,14 @@ namespace celix {
/**
* @brief Get the framework UUID.
*/
- std::string getUUID() const {
+ [[nodiscard]] std::string getUUID() const {
return std::string{celix_framework_getUUID(cFw.get())};
}
/**
* @brief Get the bundle context for the framework.
*/
- std::shared_ptr<celix::BundleContext> getFrameworkBundleContext() const {
+ [[nodiscard]] std::shared_ptr<celix::BundleContext> getFrameworkBundleContext() const {
return fwCtx;
}
@@ -105,7 +105,7 @@ namespace celix {
* @warning Try not the depend on the C API from a C++ bundle. If features are missing these should be added to
* the C++ API.
*/
- celix_framework_t * getCFramework() const {
+ [[nodiscard]] celix_framework_t * getCFramework() const {
return cFw.get();
}
private:
diff --git a/libs/framework/include/celix/FrameworkFactory.h b/libs/framework/include/celix/FrameworkFactory.h
index ad5effc..4f1f3a2 100644
--- a/libs/framework/include/celix/FrameworkFactory.h
+++ b/libs/framework/include/celix/FrameworkFactory.h
@@ -30,7 +30,7 @@ namespace celix {
/**
* @brief Create a new celix Framework instance.
*/
- static std::shared_ptr<celix::Framework> createFramework(const celix::Properties& properties = {}) {
+ inline std::shared_ptr<celix::Framework> createFramework(const celix::Properties& properties = {}) {
auto* copy = celix_properties_copy(properties.getCProperties());
auto* cFw= celix_frameworkFactory_createFramework(copy);
auto fwCtx = std::make_shared<celix::BundleContext>(celix_framework_getFrameworkContext(cFw));
diff --git a/libs/framework/include/celix/ServiceRegistrationBuilder.h b/libs/framework/include/celix/ServiceRegistrationBuilder.h
index dcbe087..b4798a6 100644
--- a/libs/framework/include/celix/ServiceRegistrationBuilder.h
+++ b/libs/framework/include/celix/ServiceRegistrationBuilder.h
@@ -23,6 +23,7 @@
#include <vector>
#include <memory>
+#include "celix/Utils.h"
#include "celix/ServiceRegistration.h"
namespace celix {
@@ -39,7 +40,7 @@ namespace celix {
friend class BundleContext;
//NOTE private to prevent move so that a build() call cannot be forgotten
- ServiceRegistrationBuilder(ServiceRegistrationBuilder&&) = default;
+ ServiceRegistrationBuilder(ServiceRegistrationBuilder&&) noexcept = default;
public:
ServiceRegistrationBuilder(
std::shared_ptr<celix_bundle_context_t> _cCtx,
@@ -50,6 +51,7 @@ namespace celix {
cCtx{std::move(_cCtx)},
svc{std::move(_svc)},
name{std::move(_name)},
+ version{celix::typeVersion<I>()},
registerAsync{_registerAsync},
unregisterAsync{_unregisterAsync}{}
@@ -69,14 +71,14 @@ namespace celix {
*
* If a key is already present the value will be overridden.
*/
- ServiceRegistrationBuilder& addProperty(std::string key, std::string value) { properties.set(std::move(key), std::move(value)); return *this; }
+ ServiceRegistrationBuilder& addProperty(const std::string& key, const std::string& value) { properties.set(key, value); return *this; }
/**
* @brief Add a property to the service properties.
*
* If a key is already present the value will be overridden.
*/
- ServiceRegistrationBuilder& addProperty(std::string key, const char* value) { properties.set(std::move(key), std::string{value}); return *this; }
+ ServiceRegistrationBuilder& addProperty(const std::string& key, const char* value) { properties.set(key, std::string{value}); return *this; }
/**
* @brief Add a property to the service properties.
@@ -84,7 +86,7 @@ namespace celix {
* If a key is already present the value will be overridden.
*/
template<typename T>
- ServiceRegistrationBuilder& addProperty(std::string key, T value) { properties.set(std::move(key), std::to_string(std::move(value))); return *this; }
+ ServiceRegistrationBuilder& addProperty(const std::string& key, T value) { properties.set(key, std::to_string(std::move(value))); return *this; }
/**
* @brief Set the service properties.
@@ -192,9 +194,9 @@ namespace celix {
const std::shared_ptr<celix_bundle_context_t> cCtx;
std::shared_ptr<I> svc;
std::string name;
+ std::string version;
bool registerAsync;
bool unregisterAsync;
- std::string version{};
celix::Properties properties{};
std::vector<std::function<void(ServiceRegistration&)>> onRegisteredCallbacks{};
std::vector<std::function<void(ServiceRegistration&)>> onUnregisteredCallbacks{};
diff --git a/libs/framework/include/celix/TrackerBuilders.h b/libs/framework/include/celix/TrackerBuilders.h
index bed7f3c..f4acc0b 100644
--- a/libs/framework/include/celix/TrackerBuilders.h
+++ b/libs/framework/include/celix/TrackerBuilders.h
@@ -40,7 +40,7 @@ namespace celix {
friend class BundleContext;
//NOTE private to prevent move so that a build() call cannot be forgotten
- ServiceTrackerBuilder(ServiceTrackerBuilder&&) = default;
+ ServiceTrackerBuilder(ServiceTrackerBuilder&&) noexcept = default;
public:
explicit ServiceTrackerBuilder(std::shared_ptr<celix_bundle_context_t> _cCtx, std::string _name) :
cCtx{std::move(_cCtx)},
@@ -57,7 +57,7 @@ namespace celix {
* Example:
* "(property_key=value)"
*/
- ServiceTrackerBuilder& setFilter(std::string f) { filter = celix::Filter{std::move(f)}; return *this; }
+ ServiceTrackerBuilder& setFilter(const std::string& f) { filter = celix::Filter{f}; return *this; }
/**
* @brief Set filter to be used to matching services.
@@ -74,8 +74,7 @@ namespace celix {
*/
template<typename F>
ServiceTrackerBuilder& addAddCallback(F&& add) {
- //TODO improve capture with move when for C++14 is available
- addCallbacks.emplace_back([add](const std::shared_ptr<I>& svc, const std::shared_ptr<const celix::Properties>&, const std::shared_ptr<const celix::Bundle>&) {
+ addCallbacks.emplace_back([add = std::forward<F>(add)](const std::shared_ptr<I>& svc, const std::shared_ptr<const celix::Properties>&, const std::shared_ptr<const celix::Bundle>&) {
add(svc);
});
return *this;
@@ -92,8 +91,7 @@ namespace celix {
*/
template<typename F>
ServiceTrackerBuilder& addAddWithPropertiesCallback(F&& add) {
- //TODO improve capture with forward when for C++14 is available
- addCallbacks.emplace_back([add](const std::shared_ptr<I>& svc, const std::shared_ptr<const celix::Properties>& props, const std::shared_ptr<const celix::Bundle>&) {
+ addCallbacks.emplace_back([add = std::forward<F>(add)](const std::shared_ptr<I>& svc, const std::shared_ptr<const celix::Properties>& props, const std::shared_ptr<const celix::Bundle>&) {
add(svc, props);
});
return *this;
@@ -109,8 +107,7 @@ namespace celix {
*/
template<typename F>
ServiceTrackerBuilder& addAddWithOwnerCallback(F&& add) {
- //TODO improve capture with forward when for C++14 is available
- addCallbacks.emplace_back(std::move(add));
+ addCallbacks.emplace_back(std::forward<F>(add));
return *this;
}
@@ -124,8 +121,7 @@ namespace celix {
*/
template<typename F>
ServiceTrackerBuilder& addRemCallback(F&& remove) {
- //TODO improve capture with move when for C++14 is available
- remCallbacks.emplace_back([remove](const std::shared_ptr<I>& svc, const std::shared_ptr<const celix::Properties>&, const std::shared_ptr<const celix::Bundle>&) {
+ remCallbacks.emplace_back([remove = std::forward<F>(remove)](const std::shared_ptr<I>& svc, const std::shared_ptr<const celix::Properties>&, const std::shared_ptr<const celix::Bundle>&) {
remove(svc);
});
return *this;
@@ -141,8 +137,7 @@ namespace celix {
*/
template<typename F>
ServiceTrackerBuilder& addRemWithPropertiesCallback(F&& remove) {
- //TODO improve capture with move when for C++14 is available
- remCallbacks.emplace_back([remove](const std::shared_ptr<I>& svc, const std::shared_ptr<const celix::Properties>& props, const std::shared_ptr<const celix::Bundle>&) {
+ remCallbacks.emplace_back([remove = std::forward<F>(remove)](const std::shared_ptr<I>& svc, const std::shared_ptr<const celix::Properties>& props, const std::shared_ptr<const celix::Bundle>&) {
remove(svc, props);
});
return *this;
@@ -158,7 +153,7 @@ namespace celix {
*/
template<typename F>
ServiceTrackerBuilder& addRemWithOwnerCallback(F&& remove) {
- remCallbacks.emplace_back(std::move(remove));
+ remCallbacks.emplace_back(std::forward<F>(remove));
return *this;
}
@@ -173,8 +168,7 @@ namespace celix {
*/
template<typename F>
ServiceTrackerBuilder& addSetCallback(F&& set) {
- //TODO improve capture with move when for C++14 is available
- setCallbacks.emplace_back([set](const std::shared_ptr<I>& svc, const std::shared_ptr<const celix::Properties>&, const std::shared_ptr<const celix::Bundle>&) {
+ setCallbacks.emplace_back([set = std::forward<F>(set)](const std::shared_ptr<I>& svc, const std::shared_ptr<const celix::Properties>&, const std::shared_ptr<const celix::Bundle>&) {
set(svc);
});
return *this;
@@ -191,9 +185,8 @@ namespace celix {
*/
template<typename F>
ServiceTrackerBuilder& addSetWithPropertiesCallback(F&& set) {
- //TODO improve capture with move when for C++14 is available
- setCallbacks.emplace_back([set](const std::shared_ptr<I>& svc, const std::shared_ptr<const celix::Properties>& props, const std::shared_ptr<const celix::Bundle>&) {
- set(svc, std::move(props));
+ setCallbacks.emplace_back([set = std::forward<F>(set)](const std::shared_ptr<I>& svc, const std::shared_ptr<const celix::Properties>& props, const std::shared_ptr<const celix::Bundle>&) {
+ set(svc, props);
});
return *this;
}
@@ -209,18 +202,10 @@ namespace celix {
*/
template<typename F>
ServiceTrackerBuilder& addSetWithOwner(F&& set) {
- setCallbacks.emplace_back(std::move(set));
+ setCallbacks.emplace_back(std::forward<F>(set));
return *this;
}
-// /**
-// * TODO
-// */
-// ServiceTrackerBuilder& addUpdateCallback(std::function<void(std::vector<std::shared_ptr<I>>)> update) {
-// //TODO update -> vector of ordered (svc rank) services
-// return *this;
-// }
-
/**
* @brief "Builds" the service tracker and returns a ServiceTracker.
*
diff --git a/libs/framework/include/celix/Trackers.h b/libs/framework/include/celix/Trackers.h
index 5e8002a..bcd849d 100644
--- a/libs/framework/include/celix/Trackers.h
+++ b/libs/framework/include/celix/Trackers.h
@@ -368,9 +368,9 @@ namespace celix {
}
protected:
struct SvcEntry {
- SvcEntry(long _svcId, long _svcRanking, const std::shared_ptr<I> _svc,
- const std::shared_ptr<const celix::Properties> _properties,
- const std::shared_ptr<const celix::Bundle> _owner) : svcId(_svcId), svcRanking(_svcRanking),
+ SvcEntry(long _svcId, long _svcRanking, std::shared_ptr<I> _svc,
+ std::shared_ptr<const celix::Properties> _properties,
+ std::shared_ptr<const celix::Bundle> _owner) : svcId(_svcId), svcRanking(_svcRanking),
svc(std::move(_svc)),
properties(std::move(_properties)),
owner(std::move(_owner)) {}
@@ -527,15 +527,16 @@ namespace celix {
}
}
- const std::chrono::milliseconds warningTimoutForNonExpiredSvcObject{1000}; //TODO make configureable with buidler
+ const std::chrono::milliseconds warningTimoutForNonExpiredSvcObject{1000};
const 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;
const 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;
const 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;
- const std::vector<std::function<void(const std::vector<std::shared_ptr<I>>)>> updateCallbacks{}; //TODO add to ctor, builder and test
- const std::vector<std::function<void(const std::vector<std::pair<std::shared_ptr<I>, std::shared_ptr<const celix::Properties>>>)>> updateWithPropertiesCallbacks{}; //TODO add to ctor, builder and test
- const std::vector<std::function<void(const std::vector<std::tuple<std::shared_ptr<I>, std::shared_ptr<const celix::Properties>, std::shared_ptr<const celix::Bundle>>>)>> updateWithOwnerCallbacks{}; //TODO add to ctor, builder and test
+ //NOTE update callbacks cannot yet be configured
+ const std::vector<std::function<void(const std::vector<std::shared_ptr<I>>)>> updateCallbacks{};
+ const std::vector<std::function<void(const std::vector<std::pair<std::shared_ptr<I>, std::shared_ptr<const celix::Properties>>>)>> updateWithPropertiesCallbacks{};
+ const std::vector<std::function<void(const std::vector<std::tuple<std::shared_ptr<I>, std::shared_ptr<const celix::Properties>, std::shared_ptr<const celix::Bundle>>>)>> updateWithOwnerCallbacks{};
struct SvcEntryCompare {
bool operator() (const std::shared_ptr<SvcEntry>& a, const std::shared_ptr<SvcEntry>& b) const {
@@ -618,21 +619,21 @@ namespace celix {
opts.callbackHandle = this;
opts.onInstalled = [](void *handle, const celix_bundle_t *cBnd) {
auto tracker = static_cast<BundleTracker *>(handle);
- auto bnd = celix::Bundle{const_cast<celix_bundle_t *>(cBnd)};
+ celix::Bundle bnd{const_cast<celix_bundle_t *>(cBnd)};
for (const auto& cb : tracker->onInstallCallbacks) {
cb(bnd);
}
};
opts.onStarted = [](void *handle, const celix_bundle_t *cBnd) {
auto tracker = static_cast<BundleTracker *>(handle);
- auto bnd = celix::Bundle{const_cast<celix_bundle_t *>(cBnd)};
+ celix::Bundle bnd{const_cast<celix_bundle_t *>(cBnd)};
for (const auto& cb : tracker->onStartCallbacks) {
cb(bnd);
}
};
opts.onStopped = [](void *handle, const celix_bundle_t *cBnd) {
auto tracker = static_cast<BundleTracker *>(handle);
- auto bnd = celix::Bundle{const_cast<celix_bundle_t *>(cBnd)};
+ celix::Bundle bnd{const_cast<celix_bundle_t *>(cBnd)};
for (const auto& cb : tracker->onStopCallbacks) {
cb(bnd);
}
diff --git a/libs/framework/include/celix/UseServiceBuilder.h b/libs/framework/include/celix/UseServiceBuilder.h
index 1bf9ddb..c504cfd 100644
--- a/libs/framework/include/celix/UseServiceBuilder.h
+++ b/libs/framework/include/celix/UseServiceBuilder.h
@@ -52,7 +52,7 @@ namespace celix {
friend class BundleContext;
//NOTE private to prevent move so that a build() call cannot be forgotten
- UseServiceBuilder(UseServiceBuilder&&) = default;
+ UseServiceBuilder(UseServiceBuilder&&) noexcept = default;
public:
explicit UseServiceBuilder(std::shared_ptr<celix_bundle_context_t> _cCtx, std::string _name, bool _useSingleService = true) :
cCtx{std::move(_cCtx)},
@@ -71,7 +71,7 @@ namespace celix {
* Example:
* "(property_key=value)"
*/
- UseServiceBuilder& setFilter(std::string f) { filter = celix::Filter{std::move(f)}; return *this; }
+ UseServiceBuilder& setFilter(const std::string& f) { filter = celix::Filter{f}; return *this; }
/**
* @brief Set filter to be used to matching services.
@@ -155,7 +155,7 @@ namespace celix {
opts.useWithOwner = [](void* data, void *voidSvc, const celix_properties_t* cProps, const celix_bundle_t* cBnd) {
auto* builder = static_cast<UseServiceBuilder<I>*>(data);
auto* svc = static_cast<I*>(voidSvc);
- const Bundle bnd = Bundle{const_cast<celix_bundle_t*>(cBnd)};
+ const Bundle bnd{const_cast<celix_bundle_t*>(cBnd)};
auto props = celix::Properties::wrap(cProps);
for (const auto& func : builder->callbacks) {
func(*svc);
diff --git a/libs/framework/include/celix/Utils.h b/libs/framework/include/celix/Utils.h
deleted file mode 100644
index db00a03..0000000
--- a/libs/framework/include/celix/Utils.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#pragma once
-
-
-#include <string>
-#include <string.h>
-#include <iostream>
-#include <vector>
-
-//NOTE based on has_rtti.cpp
-#if defined(__clang__)
-#if __has_feature(cxx_rtti)
-#define CELIX_RTTI_ENABLED
-#endif
-#elif defined(__GNUG__)
-#if defined(__GXX_RTTI)
-#define CELIX_RTTI_ENABLED
-#endif
-#elif defined(_MSC_VER)
-#if defined(_CPPRTTI)
-#define CELIX_RTTI_ENABLED
-#endif
-#endif
-
-//FORCE DISABLE RTTI
-//TODO #323 add test CI job to test rtti based type name infer
-#undef CELIX_RTTI_ENABLED
-
-#ifdef CELIX_RTTI_ENABLED
-#include <cxxabi.h>
-#endif
-
-namespace celix {
- /**
- * @brief Returns the deferred type name for the template I
- */
- template<typename INTERFACE_TYPENAME>
- std::string typeName() {
- std::string result;
-
-#ifdef CELIX_RTTI_ENABLED
- result = typeid(INTERFACE_TYPENAME).name();
- int status = 0;
- char* demangled_name {abi::__cxa_demangle(result.c_str(), NULL, NULL, &status)};
- if(status == 0) {
- result = std::string{demangled_name};
- free(demangled_name);
- }
-#else
- const char *templateStr = "INTERFACE_TYPENAME = ";
- const size_t templateStrLen = strlen(templateStr);
-
- result = __PRETTY_FUNCTION__; //USING pretty function to retrieve the filled in template argument without using typeid()
- size_t bpos = result.find(templateStr) + templateStrLen; //find begin pos after INTERFACE_TYPENAME = entry
- size_t epos = bpos;
- while (isalnum(result[epos]) || result[epos] == '_' || result[epos] == ':') {
- epos += 1;
- }
- size_t len = epos - bpos;
- result = result.substr(bpos, len);
-#endif
-
-// std::cout << "PRETTY IS '" << __PRETTY_FUNCTION__ << "'\n";
-// std::cout << "RESULT IS '" << result << "'\n";
-
- if (result.empty()) {
- std::cerr << "Cannot infer type name in function call '" << __PRETTY_FUNCTION__ << "'\n'";
- }
-
-
- return result;
- }
-
- /**
- * @brief Returns the deferred type name for the template I if the providedTypeName is empty.
- *
- * If the providedTypeName is not empty, the providedTypeName will be returned.
- */
- template<typename I>
- std::string typeName(const std::string& providedTypeName) {
- return providedTypeName.empty() ? celix::typeName<I>() : providedTypeName;
- }
-
- /**
- * @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 = 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(", ", found);
- result.emplace_back(str.substr(found, pos - found));
- }
- return result;
- }
-}
-
-#undef CELIX_RTTI_ENABLED
\ No newline at end of file
diff --git a/libs/framework/include/celix/dm/Component_Impl.h b/libs/framework/include/celix/dm/Component_Impl.h
index da3ff5d..d860afa 100644
--- a/libs/framework/include/celix/dm/Component_Impl.h
+++ b/libs/framework/include/celix/dm/Component_Impl.h
@@ -59,7 +59,7 @@ Component<T>::Component(
std::string uuid) : BaseComponent(
context,
cDepMan,
- name.empty() ? celix::typeName<T>() : std::move(name),
+ celix::typeName<T>(name),
std::move(uuid)) {}
template<class T>
@@ -93,6 +93,10 @@ Component<T>& Component<T>::addInterface(const std::string &version, const Prope
if (serviceName.empty()) {
std::cerr << "Cannot add interface, because type name could not be inferred. function: '" << __PRETTY_FUNCTION__ << "'\n";
}
+ auto svcVersion = celix::typeVersion<I>(version);
+ if (!svcVersion.empty()) {
+ properties[celix::SERVICE_VERSION] = std::move(svcVersion);
+ }
return this->addInterfaceWithName<I>(serviceName, version, properties);
}
@@ -163,7 +167,7 @@ Component<T>& Component<T>::remove(CServiceDependency<T,I>& dep) {
template<class T>
std::shared_ptr<Component<T>> Component<T>::create(celix_bundle_context_t *context, celix_dependency_manager_t* cDepMan, std::string name, std::string uuid) {
- std::string cmpName = name.empty() ? celix::typeName<T>() : std::move(name);
+ std::string cmpName = celix::typeName<T>(name);
return std::shared_ptr<Component<T>>{new Component<T>(context, cDepMan, std::move(cmpName), std::move(uuid)), [](Component<T>* cmp){
//Using a callback of async destroy to ensure that the cmp instance is still exist while the
//dm component is async disabled and destroyed.
@@ -405,6 +409,10 @@ ProvidedService<T, I> &Component<T>::createProvidedService(std::string serviceNa
I* svcPtr = &this->getInstance();
auto provide = std::make_shared<ProvidedService<T,I>>(cComponent(), serviceName, svcPtr, true);
+ auto svcVersion = celix::typeVersion<I>();
+ if (!svcVersion.empty()) {
+ provide->addProperty(celix::SERVICE_VERSION, std::move(svcVersion));
+ }
std::lock_guard<std::mutex> lck{mutex};
providedServices.push_back(provide);
return *provide;
diff --git a/libs/framework/include/celix_bundle.h b/libs/framework/include/celix_bundle.h
index ae97ab2..53913eb 100644
--- a/libs/framework/include/celix_bundle.h
+++ b/libs/framework/include/celix_bundle.h
@@ -30,21 +30,21 @@ extern "C" {
#endif
/**
- * Returns the bundle id.
+ * @brief Returns the bundle id.
* @param bnd The bundle
* @return The bundle id or < 0 if something went wrong.
*/
long celix_bundle_getId(const celix_bundle_t *bnd);
/**
- * Returns the bundle state.
+ * @brief Returns the bundle state.
* @param bnd The bundle
* @return The bundle state or OSGI_FRAMEWORK_BUNDLE_UNKNOWN if something went wrong.
*/
celix_bundle_state_e celix_bundle_getState(const celix_bundle_t *bnd);
/**
- * Returns a the use-able entry path for the provided relative path to a bundle resource.
+ * @brief Returns a the use-able entry path for the provided relative path to a bundle resource.
*
* For example if there is a resource entry in the bundle at path 'META-INF/descriptors/foo.descriptor` this call
* will return a absolute or relative path to the extracted location of the bundle resource, e.g.:
@@ -57,19 +57,31 @@ celix_bundle_state_e celix_bundle_getState(const celix_bundle_t *bnd);
char* celix_bundle_getEntry(const celix_bundle_t* bnd, const char *path);
/**
- * Returns the group of the bundle. Groups are used to order bundles.
+ * @brief Returns the group of the bundle. Groups are used to order bundles.
* Note the return value is valid as long as the bundle is installed.
*/
const char* celix_bundle_getGroup(const celix_bundle_t *bnd);
/**
- * Returns the symbolic name of the bundle.
+ * @brief Returns the symbolic name of the bundle.
* Note the return value is valid as long as the bundle is installed.
*/
const char* celix_bundle_getSymbolicName(const celix_bundle_t *bnd);
/**
- * Returns whether the bundle is the system bundle.
+ * @brief Returns the name of the bundle.
+ * Note the return value is valid as long as the bundle is installed.
+ */
+const char* celix_bundle_getName(const celix_bundle_t* bnd);
+
+/**
+ * @brief Returns the description of the bundle.
+ * Note the return value is valid as long as the bundle is installed.
+ */
+const char* celix_bundle_getDescription(const celix_bundle_t* bnd);
+
+/**
+ * @brief Returns whether the bundle is the system bundle.
*/
bool celix_bundle_isSystemBundle(const celix_bundle_t *bnd);
diff --git a/libs/framework/include/celix_bundle_activator.h b/libs/framework/include/celix_bundle_activator.h
index 623319b..7070f25 100644
--- a/libs/framework/include/celix_bundle_activator.h
+++ b/libs/framework/include/celix_bundle_activator.h
@@ -29,7 +29,8 @@ extern "C" {
#endif
/**
- * Called when this bundle is started so the bundle can create an instance for its activator.
+ * @brief Called when this bundle is started so the bundle can create an instance for its activator.
+ *
* The framework does not assume any type for the activator instance, this is implementation specific.
* The activator instance is handle as a void pointer by the framework, the implementation must cast it to the
* implementation specific type.
@@ -45,9 +46,10 @@ extern "C" {
celix_status_t celix_bundleActivator_create(celix_bundle_context_t *ctx, void **userData);
/**
- * Called when this bundle is started so the Framework can perform the bundle-specific activities necessary
- * to start this bundle. This method can be used to register services or to allocate any resources that this
- * bundle needs.
+ * @brief Called when this bundle is started so the Framework can perform the bundle-specific activities necessary
+ * to start this bundle.
+ *
+ * This method can be used to register services or to allocate any resources that this bundle needs.
*
* <p>
* This method must complete and return to its caller in a timely manner.
@@ -63,8 +65,10 @@ celix_status_t celix_bundleActivator_create(celix_bundle_context_t *ctx, void **
celix_status_t celix_bundleActivator_start(void *userData, celix_bundle_context_t *ctx);
/**
- * Called when this bundle is stopped so the Framework can perform the bundle-specific activities necessary
- * to stop the bundle. In general, this method should undo the work that the <code>bundleActivator_start()</code>
+ * @brief Called when this bundle is stopped so the Framework can perform the bundle-specific activities necessary
+ * to stop the bundle.
+ *
+ * In general, this method should undo the work that the <code>bundleActivator_start()</code>
* function started. There should be no active threads that were started by this bundle when this bundle returns.
* A stopped bundle must not call any Framework objects.
*
@@ -82,8 +86,9 @@ celix_status_t celix_bundleActivator_start(void *userData, celix_bundle_context_
celix_status_t celix_bundleActivator_stop(void *userData, celix_bundle_context_t *ctx);
/**
- * Called when this bundle is stopped so the bundle can destroy the instance of its activator. In general, this
- * method should undo the work that the <code>bundleActivator_create()</code> function initialized.
+ * @brief Called when this bundle is stopped so the bundle can destroy the instance of its activator.
+ *
+ * In general, this method should undo the work that the <code>bundleActivator_create()</code> function initialized.
*
* <p>
* This method must complete and return to its caller in a timely manner.
@@ -98,9 +103,14 @@ celix_status_t celix_bundleActivator_stop(void *userData, celix_bundle_context_t
*/
celix_status_t celix_bundleActivator_destroy(void *userData, celix_bundle_context_t* ctx);
+/**
+ * @brief Returns the C bundle context.
+ */
+celix_bundle_context_t* celix_bundleActivator_getBundleContext();
/**
- * This macro generates the required bundle activator functions for C.
+ * @brief This macro generates the required bundle activator functions for C.
+ *
* This can be used to more type safe bundle activator entries.
*
* The macro will create the following bundle activator functions:
@@ -113,7 +123,19 @@ celix_status_t celix_bundleActivator_destroy(void *userData, celix_bundle_contex
* @param stop the activator actStop function with the following signature: celix_status_t (*)(<actType>*, celix_bundle_context_t*).
*/
#define CELIX_GEN_BUNDLE_ACTIVATOR(actType, actStart, actStop) \
-celix_status_t celix_bundleActivator_create(celix_bundle_context_t *ctx __attribute__((unused)), void **userData) { \
+ \
+static celix_bundle_context_t* celix_currentBundleContext = NULL; \
+ \
+celix_bundle_context_t* celix_bundleActivator_getBundleContext() { \
+ /*celix_bundle_context_t* ctx; \
+ __atomic_load(&g_celix_currentBundleContext, &ctx, __ATOMIC_ACQUIRE); \
+ return ctx;*/ \
+ return celix_currentBundleContext; \
+} \
+ \
+celix_status_t celix_bundleActivator_create(celix_bundle_context_t *ctx, void **userData) { \
+ /*__atomic_store(&celix_currentBundleContext, &ctx, __ATOMIC_RELAXED);*/ \
+ celix_currentBundleContext = ctx; \
celix_status_t status = CELIX_SUCCESS; \
actType *data = (actType*)calloc(1, sizeof(*data)); \
if (data != NULL) { \
diff --git a/libs/framework/include/celix_bundle_context.h b/libs/framework/include/celix_bundle_context.h
index c6836a5..dd0363c 100644
--- a/libs/framework/include/celix_bundle_context.h
+++ b/libs/framework/include/celix_bundle_context.h
@@ -40,9 +40,8 @@ extern "C" {
#define OPTS_INIT
#endif
-
/**
- * Register a service to the Celix framework.
+ * @brief Register a service to the Celix framework.
*
* The service will be registered async on the Celix event loop thread. This means that service registration is (probably)
* not yet concluded when this function returns, but is added to the event loop.
@@ -58,7 +57,8 @@ extern "C" {
long celix_bundleContext_registerServiceAsync(celix_bundle_context_t *ctx, void *svc, const char *serviceName, celix_properties_t *properties);
/**
- * Register a service to the Celix framework.
+ * @brief Register a service to the Celix framework.
+ *
* Note: Please use the celix_bundleContext_registerServiceAsync instead.
*
* @param ctx The bundle context
@@ -70,7 +70,8 @@ long celix_bundleContext_registerServiceAsync(celix_bundle_context_t *ctx, void
long celix_bundleContext_registerService(celix_bundle_context_t *ctx, void *svc, const char *serviceName, celix_properties_t *properties); //__attribute__((deprecated("Use celix_bundleContext_registerServiceAsync instead!")));
/**
- * Register a service factory in the framework (for the C language).
+ * @brief Register a service factory in the framework.
+ *
* The service factory will be called for every bundle requesting/de-requesting a service. This gives the provider the
* option to create bundle specific service instances.
*
@@ -93,7 +94,8 @@ long celix_bundleContext_registerService(celix_bundle_context_t *ctx, void *svc,
long celix_bundleContext_registerServiceFactoryAsync(celix_bundle_context_t *ctx, celix_service_factory_t *factory, const char *serviceName, celix_properties_t *props);
/**
- * Register a service factory in the framework (for the C language).
+ * @brief Register a service factory in the framework.
+ *
* The service factory will be called for every bundle requesting/de-requesting a service. This gives the provider the
* option to create bundle specific service instances.
* Note: Please use the celix_bundleContext_registerServiceFactoryAsync instead.
@@ -112,11 +114,13 @@ long celix_bundleContext_registerServiceFactoryAsync(celix_bundle_context_t *ctx
long celix_bundleContext_registerServiceFactory(celix_bundle_context_t *ctx, celix_service_factory_t *factory, const char *serviceName, celix_properties_t *props); //__attribute__((deprecated("Use celix_bundleContext_registerServiceFactoryAsync instead!")));
/**
- * Service Registration Options when registering services to the Celix framework.
+ * @brief Service Registration Options when registering services to the Celix framework.
*/
typedef struct celix_service_registration_options {
/**
- * The service pointer. The actual pointer to the service. For C this is normally a pointer to a struct
+ * @brief The service pointer.
+ *
+ * The actual pointer to the service. For C this is normally a pointer to a struct
* with function pointers, but theoretically this can be a pointer to anything (e.g. a pointer to a single function,
* or a pointer to a C++ interface implementation, or just a pointer to a data structure).
*
@@ -125,7 +129,8 @@ typedef struct celix_service_registration_options {
void *svc OPTS_INIT;
/**
- * The service factory pointer.
+ * @brief The service factory pointer.
+ *
* Note if the factory service is set, the svc field will not be used.
*
* The service factory will be called for every bundle requesting/de-requesting a service. This gives the provider the
@@ -141,13 +146,17 @@ typedef struct celix_service_registration_options {
celix_service_factory_t *factory OPTS_INIT;
/**
- * The required service name. This is used to identify the service. A fully qualified name with a namespace is
+ * @brief The required service name.
+ *
+ * This is used to identify the service. A fully qualified name with a namespace is
* advisable to prevent name collision. (e.g. EXAMPLE_PRESSURE_SENSOR).
*/
const char *serviceName OPTS_INIT;
/**
- * The optional service properties. These contain meta information about the service in the
+ * @brief The optional service properties.
+ *
+ * These contain meta information about the service in the
* form of string key/values. (e.g. the location of a pressure sensor: location=left-tire).
*
* When a service is registered the Celix framework will take ownership of the provided properties.
@@ -156,12 +165,15 @@ typedef struct celix_service_registration_options {
celix_properties_t *properties OPTS_INIT;
/**
- * The optional service language. If this is NULL, CELIX_FRAMEWORK_SERVICE_LANGUAGE_C is used.
+ * @brief The optional service language.
+ *
+ * If this is NULL, CELIX_FRAMEWORK_SERVICE_LANGUAGE_C is used.
*/
const char *serviceLanguage OPTS_INIT;
/**
- * The optional service version (in the form of <MAJOR>.<MINOR>.<MICRO>.<QUALIFIER>).
+ * @brief The optional service version (in the form of <MAJOR>.<MINOR>.<MICRO>.<QUALIFIER>).
+ *
* If present consumer of the service can specific which service version range of
* a specific service they are interested in. Note that it is the responsibility of the users to ensure that
* service in those version range are compatible (binary of source). It is advisable to use semantic versioning
@@ -170,23 +182,25 @@ typedef struct celix_service_registration_options {
const char *serviceVersion OPTS_INIT;
/**
- * Async data pointer for the async register callback.
+ * @brief Async data pointer for the async register callback.
*/
void *asyncData OPTS_INIT;
/**
- * Async callback. Will be called after the a service is registered in the service registry using a async call.
- * Will be called on the Celix event loop.
+ * @brief Async callback.
+ *
+ * Will be called after the a service is registered in the service registry using a async call.
+ * Will be called on the Celix event loop.
*
* If a asyns service registration is combined with a _sync_ service unregistration, it can happen that
* unregistration happens before the registration event is processed. In this case the asyncCallback
* will not be called.
- */
+ */
void (*asyncCallback)(void *data, long serviceId) OPTS_INIT;
} celix_service_registration_options_t;
/**
- * C Macro to create a empty celix_service_registration_options_t type.
+ * @brief C Macro to create a empty celix_service_registration_options_t type.
*/
#ifndef __cplusplus
#define CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS { .svc = NULL, \
@@ -200,7 +214,7 @@ typedef struct celix_service_registration_options {
#endif
/**
- * Register a service to the Celix framework using the provided service registration options.
+ * @brief Register a service to the Celix framework using the provided service registration options.
*
* The service will be registered async on the Celix event loop thread. This means that service registration is (probably)
* not yet concluded when this function returns, but is added to the event loop..
@@ -214,7 +228,8 @@ typedef struct celix_service_registration_options {
long celix_bundleContext_registerServiceWithOptionsAsync(celix_bundle_context_t *ctx, const celix_service_registration_options_t *opts);
/**
- * Register a service to the Celix framework using the provided service registration options.
+ * @brief Register a service to the Celix framework using the provided service registration options.
+ *
* Note: Please use the celix_bundleContext_registerServiceAsyncWithOptions instead.
*
* @param ctx The bundle context
@@ -224,14 +239,16 @@ long celix_bundleContext_registerServiceWithOptionsAsync(celix_bundle_context_t
long celix_bundleContext_registerServiceWithOptions(celix_bundle_context_t *ctx, const celix_service_registration_options_t *opts); //__attribute__((deprecated("Use celix_bundleContext_registerServiceAsyncWithOptions instead!")));
/**
- * Waits til the async service registration for the provided serviceId is done.
+ * @brief Waits til the async service registration for the provided serviceId is done.
+ *
* Silently ignore service ids < 0.
* Will directly return if there is no pending service registration for the provided service id.
*/
void celix_bundleContext_waitForAsyncRegistration(celix_bundle_context_t* ctx, long serviceId);
/**
- * Checks whether a service for the provided service id is registered in the service registry.
+ * @brief Checks whether a service for the provided service id is registered in the service registry.
+ *
* Note return false if the service for the provided service id is still pending in the event loop.
* Silently ignore service ids < 0 (returns false).
*
@@ -241,7 +258,8 @@ bool celix_bundleContext_isServiceRegistered(celix_bundle_context_t* ctx, long s
/**
- * Unregister the service or service factory with service id.
+ * @brief Unregister the service or service factory with service id.
+ *
* The service will only be unregistered if the bundle of the bundle context is the owner of the service.
*
* Will log an error if service id is unknown. Will silently ignore services ids < 0.
@@ -253,7 +271,8 @@ void celix_bundleContext_unregisterService(celix_bundle_context_t *ctx, long ser
/**
- * Unregister the service or service factory with service id.
+ * @brief Unregister the service or service factory with service id.
+ *
* The service will only be unregistered if the bundle of the bundle context is the owner of the service.
*
* The service will be umregistered async on the Celix event loop thread. This means that service unregistration is (probably)
@@ -269,7 +288,8 @@ void celix_bundleContext_unregisterServiceAsync(celix_bundle_context_t *ctx, lon
/**
- * Waits til the async service unregistration for the provided serviceId is done.
+ * @brief Waits til the async service unregistration for the provided serviceId is done.
+ *
* Silently ignore service < 0.
*/
void celix_bundleContext_waitForAsyncUnregistration(celix_bundle_context_t* ctx, long serviceId);
@@ -278,7 +298,7 @@ void celix_bundleContext_waitForAsyncUnregistration(celix_bundle_context_t* ctx,
/**
- * Finds the highest ranking service and returns the service id.
+ * @brief Finds the highest ranking service and returns the service id.
*
* @param ctx The bundle context
* @param serviceName The required service name
@@ -287,7 +307,7 @@ void celix_bundleContext_waitForAsyncUnregistration(celix_bundle_context_t* ctx,
long celix_bundleContext_findService(celix_bundle_context_t *ctx, const char *serviceName);
/**
- * Finds the services with the provided service name and returns a list of the found service ids.
+ * @brief Finds the services with the provided service name and returns a list of the found service ids.
*
* @param ctx The bundle context
* @param serviceName The required service name
@@ -296,24 +316,28 @@ long celix_bundleContext_findService(celix_bundle_context_t *ctx, const char *se
celix_array_list_t* celix_bundleContext_findServices(celix_bundle_context_t *ctx, const char *serviceName);
/**
- * Service filter options which can be used to query for certain services.
+ * @brief Service filter options which can be used to query for certain services.
*/
typedef struct celix_service_filter_options {
/**
- * The service name.
+ * @brief The service name.
+ *
* If NULL is used any services which matches the filter string will be tracked.
*/
const char* serviceName OPTS_INIT;
/**
- * The optional version range. If service are registered with a service version this attribute can be used to
+ * @brief The optional version range.
+ *
+ * If service are registered with a service version this attribute can be used to
* only select service with a version in the version range.
* It uses the maven version range format, e.g. [1.0.0,2.0.0) or [1.1.1], etc.
*/
const char* versionRange OPTS_INIT;
/**
- * LDAP filter to use for fine tuning the filtering, e.g. (|(location=middle)(location=front))
+ * @brief LDAP filter to use for fine tuning the filtering, e.g. (|(location=middle)(location=front))
+ *
* The filter will be applied to all the user provided and framework provided service properties.
*/
const char* filter OPTS_INIT;
@@ -333,7 +357,7 @@ typedef struct celix_service_filter_options {
} celix_service_filter_options_t;
/**
- * C Macro to create a empty celix_service_filter_options_t type.
+ * @brief C Macro to create a empty celix_service_filter_options_t type.
*/
#ifndef __cplusplus
#define CELIX_EMPTY_SERVICE_FILTER_OPTIONS {.serviceName = NULL, .versionRange = NULL, .filter = NULL, .serviceLanguage = NULL, .ignoreServiceLanguage = false}
@@ -341,7 +365,7 @@ typedef struct celix_service_filter_options {
/**
- * Finds the highest ranking service and returns the service id.
+ * @brief Finds the highest ranking service and returns the service id.
*
* @param ctx The bundle context
* @param opts The pointer to the filter options.
@@ -350,7 +374,7 @@ typedef struct celix_service_filter_options {
long celix_bundleContext_findServiceWithOptions(celix_bundle_context_t *ctx, const celix_service_filter_options_t *opts);
/**
- * Finds the services conform the provider filter options and returns a list of the found service ids.
+ * @brief Finds the services conform the provider filter options and returns a list of the found service ids.
*
* @param ctx The bundle context
* @param opts The pointer to the filter options.
@@ -359,7 +383,8 @@ long celix_bundleContext_findServiceWithOptions(celix_bundle_context_t *ctx, con
celix_array_list_t* celix_bundleContext_findServicesWithOptions(celix_bundle_context_t *ctx, const celix_service_filter_options_t *opts);
/**
- * track the highest ranking service with the provided serviceName.
+ * @brief Track the highest ranking service with the provided serviceName.
+ *
* The highest ranking services will used for the callback.
* If a new and higher ranking services the callback with be called again with the new service.
* If a service is removed a the callback with be called with next highest ranking service or NULL as service.
@@ -382,7 +407,8 @@ long celix_bundleContext_trackServiceAsync(
);
/**
- * track the highest ranking service with the provided serviceName.
+ * @brief Track the highest ranking service with the provided serviceName.
+ *
* The highest ranking services will used for the callback.
* If a new and higher ranking services the callback with be called again with the new service.
* If a service is removed a the callback with be called with next highest ranking service or NULL as service.
@@ -403,7 +429,7 @@ long celix_bundleContext_trackService(
); //__attribute__((deprecated("Use celix_bundleContext_trackServiceSync instead!")));
/**
- * track services with the provided serviceName.
+ * @brief Track services with the provided serviceName.
*
* The service tracker will be created async on the Celix event loop thread. This means that the function can return
* before the tracker is created.
@@ -425,7 +451,8 @@ long celix_bundleContext_trackServicesAsync(
);
/**
- * track services with the provided serviceName.
+ * @brief Track services with the provided serviceName.
+ *
* Note: Please use the celix_bundleContext_trackServicesAsync instead.
*
* @param ctx The bundle context.
@@ -445,21 +472,21 @@ long celix_bundleContext_trackServices(
); //__attribute__((deprecated("Use celix_bundleContext_trackServicesAsync instead!")));;
/**
- * Service Tracker Options used to fine tune which services to track and the callback to be used for the tracked services.
+ * @brief Service Tracker Options used to fine tune which services to track and the callback to be used for the tracked services.
*/
typedef struct celix_service_tracking_options {
/**
- * The service filter options, used to setup the filter for the service to track.
+ * @brief The service filter options, used to setup the filter for the service to track.
*/
celix_service_filter_options_t filter OPTS_INIT;
/**
- * The optional callback pointer used in all the provided callback function (set, add, remove, setWithProperties, etc).
+ * @brief The optional callback pointer used in all the provided callback function (set, add, remove, setWithProperties, etc).
*/
void* callbackHandle OPTS_INIT;
/**
- * The optional set callback will be called when a new highest ranking service is available conform the provided
+ * @brief The optional set callback will be called when a new highest ranking service is available conform the provided
* service filter options.
* @param handle The callbackHandle pointer as provided in the service tracker options.
* @param svc The service pointer of the highest ranking service.
@@ -467,19 +494,19 @@ typedef struct celix_service_tracking_options {
void (*set)(void *handle, void *svc) OPTS_INIT;
/**
- * The optional setWithProperties callback is handled as the set callback, but with the addition that the service properties
+ * @brief The optional setWithProperties callback is handled as the set callback, but with the addition that the service properties
* will also be provided to the callback.
*/
void (*setWithProperties)(void *handle, void *svc, const celix_properties_t *props) OPTS_INIT; //highest ranking
/**
- * The optional setWithOwner callback is handled as the set callback, but with the addition that the service properties
+ * @brief The optional setWithOwner callback is handled as the set callback, but with the addition that the service properties
* and the bundle owning the service will also be provided to the callback.
*/
void (*setWithOwner)(void *handle, void *svc, const celix_properties_t *props, const celix_bundle_t *svcOwner) OPTS_INIT; //highest ranking
/**
- * The optional add callback will be called for every current and future service found conform the provided service filter
+ * @brief The optional add callback will be called for every current and future service found conform the provided service filter
* options as long as the tracker is active.
* @param handle The callbackHandle pointer as provided in the service tracker options.
* @param svc The service pointer of a service matching the provided service filter options.
@@ -487,19 +514,19 @@ typedef struct celix_service_tracking_options {
void (*add)(void *handle, void *svc) OPTS_INIT;
/**
- * The optional addWithProperties callback is handled as the add callback, but with the addition that the service properties
+ * @brief The optional addWithProperties callback is handled as the add callback, but with the addition that the service properties
* will also be provided to the callback.
*/
void (*addWithProperties)(void *handle, void *svc, const celix_properties_t *props) OPTS_INIT;
/**
- * The optional addWithOwner callback is handled as the add callback, but with the addition that the service properties
+ * @brief The optional addWithOwner callback is handled as the add callback, but with the addition that the service properties
* and the bundle owning the service will also be provided to the callback.
*/
void (*addWithOwner)(void *handle, void *svc, const celix_properties_t *props, const celix_bundle_t *svcOwner) OPTS_INIT;
/**
- * The optional remove callback will be called for every service conform the provided service filter options that is
+ * @brief The optional remove callback will be called for every service conform the provided service filter options that is
* unregistered. When the remove call is finished the removed services should be considered invalid. This means
* that the callback provider should ensure that the removed service is not in use or going to be used after the
* remove callback is finished.
@@ -510,25 +537,25 @@ typedef struct celix_service_tracking_options {
void (*remove)(void *handle, void *svc) OPTS_INIT;
/**
- * The optional removeWithProperties callback is handled as the remove callback, but with the addition that the service properties
+ * @brief The optional removeWithProperties callback is handled as the remove callback, but with the addition that the service properties
* will also be provided to the callback.
*/
void (*removeWithProperties)(void *handle, void *svc, const celix_properties_t *props) OPTS_INIT;
/**
- * The optional removeWithOwner callback is handled as the remove callback, but with the addition that the service properties
+ * @brief The optional removeWithOwner callback is handled as the remove callback, but with the addition that the service properties
* and the bundle owning the service will also be provided to the callback.
*/
void (*removeWithOwner)(void *handle, void *svc, const celix_properties_t *props, const celix_bundle_t *svcOwner) OPTS_INIT;
/**
- * Data for the trackerCreatedCallback.
+ * @brief Data for the trackerCreatedCallback.
*/
void *trackerCreatedCallbackData OPTS_INIT;
/**
- * The callback called when the tracker has ben created (and is active) when using a async call.
+ * @brief The callback called when the tracker has ben created (and is active) when using a async call.
*
* If a asyns track service is combined with a _sync_ stop tracker, it can happen that
* "stop tracker" happens before the "create tracker" event is processed. In this case the asyncCallback
@@ -538,7 +565,7 @@ typedef struct celix_service_tracking_options {
} celix_service_tracking_options_t;
/**
- * C Macro to create a empty celix_service_tracking_options_t type.
+ * @brief C Macro to create a empty celix_service_tracking_options_t type.
*/
#ifndef __cplusplus
#define CELIX_EMPTY_SERVICE_TRACKING_OPTIONS { .filter.serviceName = NULL, \
@@ -561,7 +588,8 @@ typedef struct celix_service_tracking_options {
#endif
/**
- * Tracks services using the provided tracker options.
+ * @brief Tracks services using the provided tracker options.
+ *
* The tracker options are only using during this call and can safely be freed/reused after this call returns.
*
* The service tracker will be created async on the Celix event loop thread. This means that the function can return
@@ -574,7 +602,8 @@ typedef struct celix_service_tracking_options {
long celix_bundleContext_trackServicesWithOptionsAsync(celix_bundle_context_t *ctx, const celix_service_tracking_options_t *opts);
/**
- * Tracks services using the provided tracker options.
+ * @brief Tracks services using the provided tracker options.
+ *
* The tracker options are only using during this call and can safely be freed/reused after this call returns.
* Note: Please use the celix_bundleContext_registerServiceFactoryAsync instead.
*
@@ -586,7 +615,8 @@ long celix_bundleContext_trackServicesWithOptionsAsync(celix_bundle_context_t *c
long celix_bundleContext_trackServicesWithOptions(celix_bundle_context_t *ctx, const celix_service_tracking_options_t *opts); //__attribute__((deprecated("Use celix_bundleContext_trackServicesWithOptionsAsync instead!")));
/**
- * Stop the tracker with the provided track id.
+ * @brief Stop the tracker with the provided track id.
+ *
* Could be a service tracker, bundle tracker or service tracker tracker.
* Only works for the trackers owned by the bundle of the bundle context.
*
@@ -605,17 +635,18 @@ void celix_bundleContext_stopTrackerAsync(
void (*doneCallback)(void* doneCallbackData));
/**
- * Wait for (async) creation of tracker
+ * @brief Wait for (async) creation of tracker
*/
void celix_bundleContext_waitForAsyncTracker(celix_bundle_context_t* ctx, long trackerId);
/**
- * Wait for (async) stopping of tracking.
+ * @brief Wait for (async) stopping of tracking.
*/
void celix_bundleContext_waitForAsyncStopTracker(celix_bundle_context_t* ctx, long trackerId);
/**
- * Stop the tracker with the provided track id.
+ * @brief Stop the tracker with the provided track id.
+ *
* Could be a service tracker, bundle tracker or service tracker tracker.
* Only works for the trackers owned by the bundle of the bundle context.
* Note: Please use the celix_bundleContext_registerServiceFactoryAsync instead.
@@ -627,7 +658,7 @@ void celix_bundleContext_stopTracker(celix_bundle_context_t *ctx, long trackerId
/**
- * Use the service with the provided service id using the provided callback. The Celix framework will ensure that
+ * @brief Use the service with the provided service id using the provided callback. The Celix framework will ensure that
* the targeted service cannot be removed during the callback.
*
* The svc is should only be considered valid during the callback.
@@ -652,8 +683,9 @@ bool celix_bundleContext_useServiceWithId(
);
/**
- * Use the highest ranking service with the provided service name using the provided callback. The Celix framework will
- * ensure that the targeted service cannot be removed during the callback.
+ * @brief Use the highest ranking service with the provided service name using the provided callback.
+ *
+ * The Celix framework will ensure that the targeted service cannot be removed during the callback.
*
* The svc is should only be considered valid during the callback.
* If no service is found the callback will not be invoked.
@@ -675,8 +707,9 @@ bool celix_bundleContext_useService(
);
/**
- * Use the services with the provided service name using the provided callback. The Celix framework will
- * ensure that the targeted service cannot be removed during the callback.
+ * @brief Use the services with the provided service name using the provided callback.
+ *
+ * The Celix framework will ensure that the targeted service cannot be removed during the callback.
*
* The svc is should only be considered valid during the callback.
* If no service is found the callback will not be invoked.
@@ -698,28 +731,28 @@ size_t celix_bundleContext_useServices(
);
/**
- * Service Use Options used to fine tune which services to use and which callbacks to use.
+ * @brief Service Use Options used to fine tune which services to use and which callbacks to use.
*/
typedef struct celix_service_use_options {
/**
- * The service filter options, used to setup the filter for the service to track.
+ * @brief The service filter options, used to setup the filter for the service to track.
*/
celix_service_filter_options_t filter OPTS_INIT;
/**
- * An optional timeout (in seconds), if > 0 the use service call will block until the timeout is expired or
+ * @brief An optional timeout (in seconds), if > 0 the use service call will block until the timeout is expired or
* when at least one service is found.
* Default (0)
*/
double waitTimeoutInSeconds OPTS_INIT;
/**
- * The optional callback pointer used in all the provided callback function (set, add, remove, setWithProperties, etc).
+ * @brief The optional callback pointer used in all the provided callback function (set, add, remove, setWithProperties, etc).
*/
void *callbackHandle OPTS_INIT;
/**
- * The optional use callback will be called when for every services found conform the service filter options
+ * @brief The optional use callback will be called when for every services found conform the service filter options
* - in case of findServices - or only for the highest ranking service found - in case of findService -.
*
* @param handle The callbackHandle pointer as provided in the service tracker options.
@@ -728,20 +761,20 @@ typedef struct celix_service_use_options {
void (*use)(void *handle, void *svc) OPTS_INIT;
/**
- * The optional useWithProperties callback is handled as the use callback, but with the addition that the service properties
+ * @brief The optional useWithProperties callback is handled as the use callback, but with the addition that the service properties
* will also be provided to the callback.
*/
void (*useWithProperties)(void *handle, void *svc, const celix_properties_t *props) OPTS_INIT;
/**
- * The optional useWithOwner callback is handled as the yse callback, but with the addition that the service properties
+ * @brief The optional useWithOwner callback is handled as the yse callback, but with the addition that the service properties
* and the bundle owning the service will also be provided to the callback.
*/
void (*useWithOwner)(void *handle, void *svc, const celix_properties_t *props, const celix_bundle_t *svcOwner) OPTS_INIT;
} celix_service_use_options_t;
/**
- * C Macro to create a empty celix_service_use_options_t type.
+ * @brief C Macro to create a empty celix_service_use_options_t type.
*/
#ifndef __cplusplus
#define CELIX_EMPTY_SERVICE_USE_OPTIONS {.filter.serviceName = NULL, \
@@ -756,8 +789,9 @@ typedef struct celix_service_use_options {
#endif
/**
- * Use the services with the provided service filter options using the provided callback. The Celix framework will
- * ensure that the targeted service cannot be removed during the callback.
+ * @brief Use the services with the provided service filter options using the provided callback.
+ *
+ * The Celix framework will ensure that the targeted service cannot be removed during the callback.
*
* The svc is should only be considered valid during the callback.
* If no service is found the callback will not be invoked.
@@ -775,8 +809,9 @@ bool celix_bundleContext_useServiceWithOptions(
/**
- * Use the services with the provided service filter options using the provided callback. The Celix framework will
- * ensure that the targeted service cannot be removed during the callback.
+ * @brief Use the services with the provided service filter options using the provided callback.
+ *
+ * The Celix framework will ensure that the targeted service cannot be removed during the callback.
*
* The svc is should only be considered valid during the callback.
* If no service is found the callback will not be invoked.
@@ -796,7 +831,7 @@ size_t celix_bundleContext_useServicesWithOptions(
/**
- * List the installed and started bundle ids.
+ * @brief List the installed and started bundle ids.
* The bundle ids does not include the framework bundle (bundle id CELIX_FRAMEWORK_BUNDLE_ID).
*
* @param ctx The bundle context
@@ -805,7 +840,7 @@ size_t celix_bundleContext_useServicesWithOptions(
celix_array_list_t* celix_bundleContext_listBundles(celix_bundle_context_t *ctx);
/**
- * Check whether a bundle is installed.
+ * @brief Check whether a bundle is installed.
* @param ctx The bundle context.
* @param bndId The bundle id to check
* @return true if the bundle is installed.
@@ -813,7 +848,7 @@ celix_array_list_t* celix_bundleContext_listBundles(celix_bundle_context_t *ctx)
bool celix_bundleContext_isBundleInstalled(celix_bundle_context_t *ctx, long bndId);
/**
- * Check whether the bundle is active.
+ * @brief Check whether the bundle is active.
* @param ctx The bundle context.
* @param bndId The bundle id to check
* @return true if the bundle is installed and active.
@@ -822,7 +857,7 @@ bool celix_bundleContext_isBundleActive(celix_bundle_context_t *ctx, long bndId)
/**
- * Install and optional start a bundle.
+ * @brief Install and optional start a bundle.
* Will silently ignore bundle ids < 0.
*
* If this function is called on the Celix event thread and autoStart is true,
@@ -838,7 +873,7 @@ bool celix_bundleContext_isBundleActive(celix_bundle_context_t *ctx, long bndId)
long celix_bundleContext_installBundle(celix_bundle_context_t *ctx, const char *bundleLoc, bool autoStart);
/**
- * Uninstall the bundle with the provided bundle id. If needed the bundle will be stopped first.
+ * @brief Uninstall the bundle with the provided bundle id. If needed the bundle will be stopped first.
* Will silently ignore bundle ids < 0.
*
* If this function is called on the Celix event thread, the actual stopping of the bundle will be done async and
@@ -853,7 +888,7 @@ long celix_bundleContext_installBundle(celix_bundle_context_t *ctx, const char *
bool celix_bundleContext_uninstallBundle(celix_bundle_context_t *ctx, long bndId);
/**
- * Stop the bundle with the provided bundle id.
+ * @brief Stop the bundle with the provided bundle id.
* Will silently ignore bundle ids < 0.
*
* If this function is called on the Celix event thread, the actual stopping of the bundle will be done async and
@@ -868,7 +903,7 @@ bool celix_bundleContext_uninstallBundle(celix_bundle_context_t *ctx, long bndId
bool celix_bundleContext_stopBundle(celix_bundle_context_t *ctx, long bndId);
/**
- * Start the bundle with the provided bundle id.
+ * @brief Start the bundle with the provided bundle id.
* Will silently ignore bundle ids < 0.
*
* If this function is called on the Celix event thread, the actual starting of the bundle will be done async and
@@ -883,7 +918,7 @@ bool celix_bundleContext_stopBundle(celix_bundle_context_t *ctx, long bndId);
bool celix_bundleContext_startBundle(celix_bundle_context_t *ctx, long bndId);
/**
- * Returns the bundle symbolic name for the provided bundle id.
+ * @brief Returns the bundle symbolic name for the provided bundle id.
* The caller is owner of the return string.
*
* @param ctx The bundle context
@@ -894,7 +929,8 @@ char* celix_bundleContext_getBundleSymbolicName(celix_bundle_context_t *ctx, lon
/**
- * track bundles
+ * @brief Track bundles.
+ *
* The add bundle callback will also be called for already installed bundles.
*
* The bundle tracker will be created async on the Celix event loop thread. This means that the function can return
@@ -914,7 +950,8 @@ long celix_bundleContext_trackBundlesAsync(
);
/**
- * track bundles
+ * @brief Track bundles.
+ *
* The add bundle callback will also be called for already installed bundles.
*
* Note: please use celix_bundleContext_trackBundlesAsync instead.
@@ -934,16 +971,16 @@ long celix_bundleContext_trackBundles(
/**
- * The Service Bundle Tracking options can be used to fine tune the requested bundle tracker options.
+ * @brief The Service Bundle Tracking options can be used to fine tune the requested bundle tracker options.
*/
typedef struct celix_bundle_tracker_options {
/**
- * The optional callback pointer used in all the provided callback function (set, add, remove, setWithProperties, etc).
+ * @brief The optional callback pointer used in all the provided callback function (set, add, remove, setWithProperties, etc).
*/
void* callbackHandle OPTS_INIT;
/**
- * Tracker callback when a bundle is installed.
+ * @brief Tracker callback when a bundle is installed.
* @param handle The handle, contains the value of the callbackHandle.
* @param bundle The bundle which has been installed.
* The bundle pointer is only guaranteed to be valid during the callback.
@@ -951,7 +988,7 @@ typedef struct celix_bundle_tracker_options {
void (*onInstalled)(void *handle, const celix_bundle_t *bundle) OPTS_INIT;
/**
- * Tracker callback when a bundle is started.
+ * @brief Tracker callback when a bundle is started.
* @param handle The handle, contains the value of the callbackHandle.
* @param bundle The bundle which has been started.
* The bundle pointer is only guaranteed to be valid during the callback.
@@ -959,7 +996,7 @@ typedef struct celix_bundle_tracker_options {
void (*onStarted)(void *handle, const celix_bundle_t *bundle) OPTS_INIT;
/**
- * Tracker callback when a bundle is stopped.
+ * @brief Tracker callback when a bundle is stopped.
* @param handle The handle, contains the value of the callbackHandle.
* @param bundle The bundle which has been stopped.
* The bundle pointer is only guaranteed to be valid during the callback.
@@ -974,18 +1011,18 @@ typedef struct celix_bundle_tracker_options {
void (*onBundleEvent)(void *handle, const celix_bundle_event_t *event) OPTS_INIT;
/**
- * Default the framework bundle (bundle id 0) will not trigger the callbacks.
+ * @brief Default the framework bundle (bundle id 0) will not trigger the callbacks.
* This is done, because the framework bundle is a special bundle which is generally not needed in the callbacks.
*/
bool includeFrameworkBundle OPTS_INIT;
/**
- * Data for the trackerCreatedCallback.
+ * @brief Data for the trackerCreatedCallback.
*/
void *trackerCreatedCallbackData OPTS_INIT;
/**
- * The callback called when the tracker has ben created (and is active) when using the
+ * @brief The callback called when the tracker has ben created (and is active) when using the
* track bundles ascync calls.
*
* If a asyns track service is combined with a _sync_ stop tracker, it can happen that
@@ -996,14 +1033,15 @@ typedef struct celix_bundle_tracker_options {
} celix_bundle_tracking_options_t;
/**
- * C Macro to create a empty celix_service_filter_options_t type.
+ * @brief C Macro to create a empty celix_service_filter_options_t type.
*/
#ifndef __cplusplus
#define CELIX_EMPTY_BUNDLE_TRACKING_OPTIONS {.callbackHandle = NULL, .onInstalled = NULL, .onStarted = NULL, .onStopped = NULL, .onBundleEvent = NULL, .includeFrameworkBundle = false, .trackerCreatedCallbackData = NULL, .trackerCreatedCallback = NULL}
#endif
/**
- * Tracks bundles using the provided bundle tracker options.
+ * @brief Tracks bundles using the provided bundle tracker options.
+ *
* The tracker options are only using during this call and can safely be freed/reused after this call returns.
* (i.e. can be on the stack)
*
@@ -1020,7 +1058,8 @@ long celix_bundleContext_trackBundlesWithOptionsAsync(
);
/**
- * Tracks bundles using the provided bundle tracker options.
+ * @brief Tracks bundles using the provided bundle tracker options.
+ *
* The tracker options are only using during this call and can safely be freed/reused after this call returns.
* (i.e. can be on the stack)
*
@@ -1036,7 +1075,8 @@ long celix_bundleContext_trackBundlesWithOptions(
); //__attribute__((deprecated("Use celix_bundleContext_trackBundlesWithOptionsAsync instead!")));
/**
- * Use the bundle with the provided bundle id if it is in the active (started) state
+ * @brief Use the bundle with the provided bundle id if it is in the active (started) state.
+ *
* The provided callback will be called if the bundle is found and in the active (started) state.
*
* @param ctx The bundle context.
@@ -1054,7 +1094,8 @@ bool celix_bundleContext_useBundle(
);
/**
- * Use the currently active (started) bundles.
+ * @brief Use the currently active (started) bundles.
+ *
* The provided callback will be called for all the currently started bundles (excluding the framework bundle).
*
* @param ctx The bundle context.
@@ -1068,22 +1109,17 @@ void celix_bundleContext_useBundles(
void (*use)(void *handle, const celix_bundle_t *bundle)
);
-
-
-//TODO add useBundleWithOptions (e.g. which state)
-//TODO findBundles
-
/**
- * Service Tracker Info provided to the service tracker tracker callbacks.
+ * @brief Service Tracker Info provided to the service tracker tracker callbacks.
*/
typedef struct celix_service_tracker_info {
/**
- * The parsed service filter, e.g. parsed "(&(objectClass=example_calc)(service.language=C)(meta.info=foo))"
+ * @brief The parsed service filter, e.g. parsed "(&(objectClass=example_calc)(service.language=C)(meta.info=foo))"
*/
celix_filter_t *filter;
/**
- *The service name filter attribute parsed from the service filter (i.e. the value of the objectClass attribute key)
+ * @brief The service name filter attribute parsed from the service filter (i.e. the value of the objectClass attribute key)
*/
const char *serviceName;
@@ -1094,14 +1130,15 @@ typedef struct celix_service_tracker_info {
const char *serviceLanguage;
/**
- * Bundle id of the owner of the service tracker.
+ * @brief Bundle id of the owner of the service tracker.
*/
long bundleId;
} celix_service_tracker_info_t;
/**
- * Track the service tracker targeting the provided service name. This can be used to track if there is an interest
- * in a certain service and ad-hoc act on that interest.
+ * @brief Track the service tracker targeting the provided service name.
+ *
+ * This can be used to track if there is an interest in a certain service and ad-hoc act on that interest.
*
* Note that the celix_service_tracker_info_t pointer in the trackerAdd/trackerRemove callbacks are only valid during
* the callback.
@@ -1135,8 +1172,9 @@ long celix_bundleContext_trackServiceTrackersAsync(
void (*doneCallback)(void* doneCallbackData));
/**
- * Track the service tracker targeting the provided service name. This can be used to track if there is an interest
- * in a certain service and ad-hoc act on that interest.
+ * @brief Track the service tracker targeting the provided service name.
+ *
+ * This can be used to track if there is an interest in a certain service and ad-hoc act on that interest.
*
* Note that the celix_service_tracker_info_t pointer in the trackerAdd/trackerRemove callbacks are only valid during
* the callback.
@@ -1162,7 +1200,7 @@ long celix_bundleContext_trackServiceTrackers(
void (*trackerRemove)(void *handle, const celix_service_tracker_info_t *info)); //__attribute__((deprecated("Use celix_bundleContext_trackServiceTrackersAsync instead!")));
/**
- * Gets the dependency manager for this bundle context.
+ * @brief Gets the dependency manager for this bundle context.
*
* @return the dependency manager or NULL if unsuccessful.
*/
@@ -1170,26 +1208,26 @@ celix_dependency_manager_t* celix_bundleContext_getDependencyManager(celix_bundl
/**
- * Wait until all Celix event for this bundle are completed.
+ * @brief Wait until all Celix event for this bundle are completed.
*/
void celix_bundleContext_waitForEvents(celix_bundle_context_t* ctx);
/**
- * Returns the bundle for this bundle context.
+ * @brief Returns the bundle for this bundle context.
*/
celix_bundle_t* celix_bundleContext_getBundle(const celix_bundle_context_t *ctx);
/**
- * Returns the bundle if for the bundle of this bundle context.
+ * @brief Returns the bundle if for the bundle of this bundle context.
*/
long celix_bundleContext_getBundleId(const celix_bundle_context_t *ctx);
celix_framework_t* celix_bundleContext_getFramework(const celix_bundle_context_t* ctx);
/**
- * Logs a message to Celix framework logger with the provided log level.
+ * @brief Logs a message to Celix framework logger with the provided log level.
* @param ctx The bundle context
* @param level The log level to use
* @param format printf style format string
@@ -1198,13 +1236,13 @@ celix_framework_t* celix_bundleContext_getFramework(const celix_bundle_context_t
void celix_bundleContext_log(const celix_bundle_context_t* ctx, celix_log_level_e level, const char* format, ...);
/**
- * Logs a message to Celix framework logger with the provided log level.
+ * @brief Logs a message to Celix framework logger with the provided log level.
*/
void celix_bundleContext_vlog(const celix_bundle_context_t* ctx, celix_log_level_e level, const char* format, va_list formatArgs);
/**
- * Gets the config property - or environment variable if the config property does not exist - for the provided name.
+ * @brief Gets the config property - or environment variable if the config property does not exist - for the provided name.
* @param key The key of the property to receive.
* @param defaultVal The default value to use if the property is not found (can be NULL).
* @return The property value for the provided key or the provided defaultValue is the key is not found.
@@ -1212,7 +1250,7 @@ void celix_bundleContext_vlog(const celix_bundle_context_t* ctx, celix_log_level
const char* celix_bundleContext_getProperty(celix_bundle_context_t *ctx, const char *key, const char *defaultVal);
/**
- * Gets the config property as converts it to long. If the property is not a valid long, the defaultValue will be returned.
+ * @brief Gets the config property as converts it to long. If the property is not a valid long, the defaultValue will be returned.
* The rest of the behaviour is the same as celix_bundleContext_getProperty.
* @param key The key of the property to receive.
@@ -1222,7 +1260,7 @@ const char* celix_bundleContext_getProperty(celix_bundle_context_t *ctx, const c
long celix_bundleContext_getPropertyAsLong(celix_bundle_context_t *ctx, const char *key, long defaultValue);
/**
- * Gets the config property as converts it to double. If the property is not a valid double, the defaultValue will be returned.
+ * @brief Gets the config property as converts it to double. If the property is not a valid double, the defaultValue will be returned.
* The rest of the behaviour is the same as celix_bundleContext_getProperty.
* @param key The key of the property to receive.
@@ -1232,7 +1270,7 @@ long celix_bundleContext_getPropertyAsLong(celix_bundle_context_t *ctx, const ch
double celix_bundleContext_getPropertyAsDouble(celix_bundle_context_t *ctx, const char *key, double defaultValue);
/**
- * Gets the config property as converts it to bool. If the property is not a valid bool, the defaultValue will be returned.
+ * @brief Gets the config property as converts it to bool. If the property is not a valid bool, the defaultValue will be returned.
* The rest of the behaviour is the same as celix_bundleContext_getProperty.
* @param key The key of the property to receive.
diff --git a/libs/framework/include/celix_constants.h b/libs/framework/include/celix_constants.h
index b013317..ec4a405 100644
--- a/libs/framework/include/celix_constants.h
+++ b/libs/framework/include/celix_constants.h
@@ -144,6 +144,9 @@ extern "C" {
#define OSGI_FRAMEWORK_DEPRECATED_BUNDLE_ACTIVATOR_DESTROY "bundleActivator_destroy"
#define CELIX_FRAMEWORK_BUNDLE_SYMBOLICNAME "Bundle-SymbolicName"
+#define CELIX_FRAMEWORK_BUNDLE_NAME "Bundle-Name"
+#define CELIX_FRAMEWORK_BUNDLE_GROUP "Bundle-Group"
+#define CELIX_FRAMEWORK_BUNDLE_DESCRIPTION "Bundle-Description"
#define CELIX_FRAMEWORK_BUNDLE_VERSION "Bundle-Version"
#define CELIX_FRAMEWORK_PRIVATE_LIBRARY "Private-Library"
#define CELIX_FRAMEWORK_EXPORT_LIBRARY "Export-Library"
@@ -270,6 +273,15 @@ extern "C" {
*/
#define CELIX_AUTO_START_6 "CELIX_AUTO_START_6"
+/**
+ * @brief Celix framework environment property (named "CELIX_FRAMEWORK_WARN_FOR_MISSING_SERVICE_VERSION")
+ * which configures the Celix framework to print warning when service are registered without a version property.
+ *
+ * Default is true.
+ */
+#define CELIX_FRAMEWORK_WARN_FOR_MISSING_SERVICE_VERSION "CELIX_FRAMEWORK_WARN_FOR_MISSING_SERVICE_VERSION"
+
+#define CELIX_FRAMEWORK_WARN_FOR_MISSING_SERVICE_VERSION_DEFAULT false
#ifdef __cplusplus
}
diff --git a/libs/framework/include/module.h b/libs/framework/include/module.h
index c37b2d3..d81ca87 100644
--- a/libs/framework/include/module.h
+++ b/libs/framework/include/module.h
@@ -89,6 +89,10 @@ FRAMEWORK_EXPORT celix_array_list_t *module_getDependents(module_pt module);
FRAMEWORK_EXPORT celix_status_t module_getGroup(module_pt module, const char **group);
+FRAMEWORK_EXPORT celix_status_t module_getName(module_pt module, const char **name);
+
+FRAMEWORK_EXPORT celix_status_t module_getDescription(module_pt module, const char **descriptoin);
+
#ifdef __cplusplus
}
#endif
diff --git a/libs/framework/src/bundle.c b/libs/framework/src/bundle.c
index 4dd20be..97cbe71 100644
--- a/libs/framework/src/bundle.c
+++ b/libs/framework/src/bundle.c
@@ -32,6 +32,7 @@
#include "bundle_context_private.h"
#include "service_tracker_private.h"
+
celix_status_t bundle_createModule(bundle_pt bundle, module_pt *module);
celix_status_t bundle_closeRevisions(const_bundle_pt bundle);
@@ -107,6 +108,9 @@ celix_status_t bundle_destroy(bundle_pt bundle) {
arrayList_destroy(bundle->modules);
free(bundle->symbolicName);
+ free(bundle->name);
+ free(bundle->group);
+ free(bundle->description);
free(bundle);
return CELIX_SUCCESS;
@@ -357,9 +361,18 @@ celix_status_t bundle_addModule(bundle_pt bundle, module_pt module) {
resolver_addModule(module);
if (bundle->symbolicName == NULL) {
const char *sn = NULL;
+ const char *n = NULL;
+ const char *g = NULL;
+ const char *d = NULL;
module_getSymbolicName(module, &sn);
+ module_getGroup(module, &g);
+ module_getName(module, &n);
+ module_getDescription(module, &d);
if (sn != NULL) {
bundle->symbolicName = celix_utils_strdup(sn);
+ bundle->name = celix_utils_strdup(n);
+ bundle->group = celix_utils_strdup(g);
+ bundle->description = celix_utils_strdup(d);
}
}
@@ -577,21 +590,21 @@ char* celix_bundle_getEntry(const bundle_t* bnd, const char *path) {
const char* celix_bundle_getGroup(const celix_bundle_t *bnd) {
- const char *result = NULL;
- if (bnd != NULL) {
- module_pt mod = NULL;
- bundle_getCurrentModule((celix_bundle_t*)bnd, &mod);
- if (mod != NULL) {
- module_getGroup(mod, &result);
- }
- }
- return result;
+ return bnd->group;
}
const char* celix_bundle_getSymbolicName(const celix_bundle_t *bnd) {
return bnd->symbolicName;
}
+const char* celix_bundle_getName(const celix_bundle_t* bnd) {
+ return bnd->name;
+}
+
+const char* celix_bundle_getDescription(const celix_bundle_t* bnd) {
+ return bnd->description;
+}
+
bool celix_bundle_isSystemBundle(const celix_bundle_t *bnd) {
return bnd != NULL && celix_bundle_getId(bnd) == 0;
}
diff --git a/libs/framework/src/bundle_context.c b/libs/framework/src/bundle_context.c
index ae9b68f..ddc2c94 100644
--- a/libs/framework/src/bundle_context.c
+++ b/libs/framework/src/bundle_context.c
@@ -39,6 +39,7 @@
#include "module.h"
#include "service_tracker_private.h"
#include "celix_array_list.h"
+#include "celix_libloader.h"
static celix_status_t bundleContext_bundleChanged(void *handle, bundle_event_t *event);
static void bundleContext_cleanupBundleTrackers(bundle_context_t *ct);
diff --git a/libs/framework/src/bundle_private.h b/libs/framework/src/bundle_private.h
index 633fcdd..cff093e 100644
--- a/libs/framework/src/bundle_private.h
+++ b/libs/framework/src/bundle_private.h
@@ -27,7 +27,10 @@
struct celix_bundle {
bundle_context_pt context;
- char *symbolicName; //for debug
+ char *symbolicName;
+ char *name;
+ char *group;
+ char *description;
struct celix_bundle_activator *activator;
bundle_state_e state;
void * handle;
diff --git a/libs/framework/src/celix_library_loader.c b/libs/framework/src/celix_libloader.c
similarity index 77%
rename from libs/framework/src/celix_library_loader.c
rename to libs/framework/src/celix_libloader.c
index 9889065..c7d855d 100644
--- a/libs/framework/src/celix_library_loader.c
+++ b/libs/framework/src/celix_libloader.c
@@ -17,31 +17,36 @@
* under the License.
*/
-#include "celix_constants.h"
-#include "celix_library_loader.h"
#include <dlfcn.h>
+#include "celix_constants.h"
+#include "celix_libloader.h"
+#include "utils.h"
+
celix_library_handle_t* celix_libloader_open(celix_bundle_context_t *ctx, const char *libPath) {
-#if defined(DEBUG) && !defined(ANDROID)
- bool def = true;
-#else
- bool def = false;
+ bool defaultNoDelete = true;
+#if defined(NDEBUG)
+ bool defaultNoDelete = false;
#endif
- bool noDelete = celix_bundleContext_getPropertyAsBool(ctx, CELIX_LOAD_BUNDLES_WITH_NODELETE, def);
+ celix_library_handle_t* handle = NULL;
+ bool noDelete = celix_bundleContext_getPropertyAsBool(ctx, CELIX_LOAD_BUNDLES_WITH_NODELETE, defaultNoDelete);
+ int flags = RTLD_LAZY|RTLD_LOCAL;
if (noDelete) {
- return dlopen(libPath, RTLD_LAZY|RTLD_LOCAL|RTLD_NODELETE);
- } else {
- return dlopen(libPath, RTLD_LAZY|RTLD_LOCAL);
+ flags = RTLD_LAZY|RTLD_LOCAL|RTLD_NODELETE;
}
+ handle = dlopen(libPath, flags);
+ return handle;
}
void celix_libloader_close(celix_library_handle_t *handle) {
dlclose(handle);
}
+
void* celix_libloader_getSymbol(celix_library_handle_t *handle, const char *name) {
return dlsym(handle, name);
}
+
const char* celix_libloader_getLastError() {
return dlerror();
}
\ No newline at end of file
diff --git a/libs/framework/src/celix_library_loader.h b/libs/framework/src/celix_libloader.h
similarity index 54%
rename from libs/framework/src/celix_library_loader.h
rename to libs/framework/src/celix_libloader.h
index f0779d1..2691b62 100644
--- a/libs/framework/src/celix_library_loader.h
+++ b/libs/framework/src/celix_libloader.h
@@ -17,16 +17,44 @@
* under the License.
*/
-#ifndef CELIX_CELIX_LIBRARY_LOADER_H
-#define CELIX_CELIX_LIBRARY_LOADER_H
+#ifndef CELIX_CELIX_LIBLOADER_H
+#define CELIX_CELIX_LIBLOADER_H
#include "celix_bundle_context.h"
typedef void celix_library_handle_t;
+/**
+ * @brief Load library using the provided path.
+ * @return a library handle or NULL if the library could not be loaded.
+ */
celix_library_handle_t* celix_libloader_open(celix_bundle_context_t *ctx, const char *libPath);
+
+/**
+ * @brief Close the library
+ */
void celix_libloader_close(celix_library_handle_t *handle);
+
+/**
+ * @brief Get the address of a symbol with the provided name.
+ * @return The symbol address of NULL if the symbol could not be found.
+ */
void* celix_libloader_getSymbol(celix_library_handle_t *handle, const char *name);
+
+/**
+ * @brief Returns the last celix_libloader_open error
+ * @return The last error or NULL.
+ */
const char* celix_libloader_getLastError();
-#endif //CELIX_CELIX_LIBRARY_LOADER_H
+/**
+ * @brief Tries to find the bundle activator library for the provided addr and if found tries to
+ * find the symbol address for the provided symbol name in the bundle activator library.
+ *
+ * @param addr A address which is use to lookup the bundle activator library (using dladdr1)
+ * @param name The symbol name to find
+ * @return The found symbol address or NULL.
+ */
+void* celix_libloader_findBundleActivatorSymbolFromAddr(void *addr, const char* name);
+
+#endif //CELIX_CELIX_LIBLOADER_H
diff --git a/libs/framework/src/framework.c b/libs/framework/src/framework.c
index e10d259..9b5caa1 100644
--- a/libs/framework/src/framework.c
+++ b/libs/framework/src/framework.c
@@ -37,8 +37,7 @@
#include "bundle_private.h"
#include "celix_bundle_context.h"
#include "bundle_context_private.h"
-#include "service_tracker.h"
-#include "celix_library_loader.h"
+#include "celix_libloader.h"
#include "celix_log_constants.h"
typedef celix_status_t (*create_function_fp)(bundle_context_t *context, void **userData);
@@ -259,7 +258,7 @@ celix_status_t framework_create(framework_pt *out, celix_properties_t* config) {
}
framework->logger = celix_frameworkLogger_create(celix_logUtils_logLevelFromString(logStr, CELIX_LOG_LEVEL_INFO));
- celix_status_t status =bundle_create(&framework->bundle);
+ celix_status_t status = bundle_create(&framework->bundle);
status = CELIX_DO_IF(status, bundle_getBundleId(framework->bundle, &framework->bundleId));
status = CELIX_DO_IF(status, bundle_setFramework(framework->bundle, framework));
status = CELIX_DO_IF(status, bundleCache_create(uuid, framework->configurationMap, &framework->cache));
diff --git a/libs/framework/src/manifest_parser.c b/libs/framework/src/manifest_parser.c
index 13a2b2e..038af09 100644
--- a/libs/framework/src/manifest_parser.c
+++ b/libs/framework/src/manifest_parser.c
@@ -45,7 +45,6 @@ struct manifestParser {
manifest_pt manifest;
version_pt bundleVersion;
- char * bundleSymbolicName;
linked_list_pt capabilities;
linked_list_pt requirements;
};
@@ -64,7 +63,6 @@ celix_status_t manifestParser_create(module_pt owner, manifest_pt manifest, mani
parser = (manifest_parser_pt) malloc(sizeof(*parser));
if (parser) {
const char * bundleVersion = NULL;
- const char * bundleSymbolicName = NULL;
parser->manifest = manifest;
parser->owner = owner;
@@ -76,10 +74,6 @@ celix_status_t manifestParser_create(module_pt owner, manifest_pt manifest, mani
parser->bundleVersion = NULL;
version_createEmptyVersion(&parser->bundleVersion);
}
- bundleSymbolicName = manifest_getValue(manifest, OSGI_FRAMEWORK_BUNDLE_SYMBOLICNAME);
- if (bundleSymbolicName != NULL) {
- parser->bundleSymbolicName = (char*)bundleSymbolicName;
- }
parser->capabilities = manifestParser_parseExportHeader(owner, manifest_getValue(manifest, OSGI_FRAMEWORK_EXPORT_LIBRARY));
parser->requirements = manifestParser_parseImportHeader(manifest_getValue(manifest, OSGI_FRAMEWORK_IMPORT_LIBRARY));
@@ -101,7 +95,6 @@ celix_status_t manifestParser_destroy(manifest_parser_pt mp) {
mp->capabilities = NULL;
linkedList_destroy(mp->requirements);
mp->requirements = NULL;
- mp->bundleSymbolicName = NULL;
version_destroy(mp->bundleVersion);
mp->bundleVersion = NULL;
mp->manifest = NULL;
@@ -465,19 +458,30 @@ static linked_list_pt manifestParser_parseExportHeader(module_pt module, const c
return capabilities;
}
+static celix_status_t manifestParser_getDuplicateEntry(manifest_parser_pt parser, const char* entryName, char **result) {
+ const char *val = manifest_getValue(parser->manifest, entryName);
+ if (result != NULL && val == NULL) {
+ *result = NULL;
+ } else if (result != NULL) {
+ *result = celix_utils_strdup(val);
+ }
+ return CELIX_SUCCESS;
+}
+
celix_status_t manifestParser_getAndDuplicateGroup(manifest_parser_pt parser, char **group) {
- const char *val = manifest_getValue(parser->manifest, "Bundle-Group");
- if (group != NULL && val == NULL) {
- *group = NULL;
- } else if (group != NULL) {
- *group = strndup(val, 1024*10);
- }
- return CELIX_SUCCESS;
+ return manifestParser_getDuplicateEntry(parser, CELIX_FRAMEWORK_BUNDLE_GROUP, group);
}
celix_status_t manifestParser_getAndDuplicateSymbolicName(manifest_parser_pt parser, char **symbolicName) {
- *symbolicName = strndup(parser->bundleSymbolicName, 1024*10);
- return CELIX_SUCCESS;
+ return manifestParser_getDuplicateEntry(parser, OSGI_FRAMEWORK_BUNDLE_SYMBOLICNAME, symbolicName);
+}
+
+celix_status_t manifestParser_getAndDuplicateName(manifest_parser_pt parser, char **name) {
+ return manifestParser_getDuplicateEntry(parser, CELIX_FRAMEWORK_BUNDLE_NAME, name);
+}
+
+celix_status_t manifestParser_getAndDuplicateDescription(manifest_parser_pt parser, char **description) {
+ return manifestParser_getDuplicateEntry(parser, CELIX_FRAMEWORK_BUNDLE_DESCRIPTION, description);
}
celix_status_t manifestParser_getBundleVersion(manifest_parser_pt parser, version_pt *version) {
diff --git a/libs/framework/src/manifest_parser.h b/libs/framework/src/manifest_parser.h
index a5d7063..0acae27 100644
--- a/libs/framework/src/manifest_parser.h
+++ b/libs/framework/src/manifest_parser.h
@@ -38,6 +38,8 @@ celix_status_t manifestParser_create(module_pt owner, manifest_pt manifest, mani
celix_status_t manifestParser_destroy(manifest_parser_pt mp);
celix_status_t manifestParser_getAndDuplicateSymbolicName(manifest_parser_pt parser, char **symbolicName);
+celix_status_t manifestParser_getAndDuplicateName(manifest_parser_pt parser, char **name);
+celix_status_t manifestParser_getAndDuplicateDescription(manifest_parser_pt parser, char **description);
celix_status_t manifestParser_getBundleVersion(manifest_parser_pt parser, version_pt *version);
celix_status_t manifestParser_getAndDuplicateGroup(manifest_parser_pt parser, char **group);
celix_status_t manifestParser_getCapabilities(manifest_parser_pt parser, linked_list_pt *capabilities);
diff --git a/libs/framework/src/module.c b/libs/framework/src/module.c
index f02f907..1a1be97 100644
--- a/libs/framework/src/module.c
+++ b/libs/framework/src/module.c
@@ -20,6 +20,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <celix_utils.h>
#include "module.h"
#include "manifest_parser.h"
@@ -33,8 +34,10 @@ struct module {
array_list_pt dependentImporters;
version_pt version;
- char * symbolicName;
- char * group;
+ char* symbolicName;
+ char* group;
+ char* name;
+ char* description;
bool resolved;
manifest_pt headerMap;
@@ -64,6 +67,12 @@ module_pt module_create(manifest_pt headerMap, const char * moduleId, bundle_pt
module->group = NULL;
manifestParser_getAndDuplicateGroup(mp, &module->group);
+ module->name = NULL;
+ manifestParser_getAndDuplicateName(mp, &module->name);
+
+ module->description = NULL;
+ manifestParser_getAndDuplicateDescription(mp, &module->description);
+
module->version = NULL;
manifestParser_getBundleVersion(mp, &module->version);
@@ -88,8 +97,10 @@ module_pt module_createFrameworkModule(bundle_pt bundle) {
module = (module_pt) calloc(1, sizeof(*module));
if (module) {
module->id = strdup("0");
- module->symbolicName = strdup("Framework");
- module->group = strdup("Celix/Framework");
+ module->symbolicName = celix_utils_strdup("celix_framework");
+ module->group = celix_utils_strdup("Celix/Framework");
+ module->name = celix_utils_strdup("Celix Framework");
+ module->description = celix_utils_strdup("The Celix Framework System Bundle");
module->version = NULL;
version_createVersion(1, 0, 0, "", &module->version);
@@ -147,7 +158,9 @@ void module_destroy(module_pt module) {
free(module->id);
free(module->symbolicName);
- free(module->group);
+ free(module->name);
+ free(module->group);
+ free(module->description);
free(module);
}
@@ -176,16 +189,44 @@ version_pt module_getVersion(module_pt module) {
celix_status_t module_getSymbolicName(module_pt module, const char **symbolicName) {
celix_status_t status = CELIX_SUCCESS;
-
if (module == NULL) {
status = CELIX_ILLEGAL_ARGUMENT;
} else {
*symbolicName = module->symbolicName;
}
-
return status;
}
+celix_status_t module_getName(module_pt module, const char **symbolicName) {
+ celix_status_t status = CELIX_SUCCESS;
+ if (module == NULL) {
+ status = CELIX_ILLEGAL_ARGUMENT;
+ } else {
+ *symbolicName = module->name;
+ }
+ return status;
+}
+
+celix_status_t module_getGroup(module_pt module, const char **symbolicName) {
+ celix_status_t status = CELIX_SUCCESS;
+ if (module == NULL) {
+ status = CELIX_ILLEGAL_ARGUMENT;
+ } else {
+ *symbolicName = module->group;
+ }
+ return status;
+}
+
+celix_status_t module_getDescription(module_pt module, const char **symbolicName) {
+ celix_status_t status = CELIX_SUCCESS;
+ if (module == NULL) {
+ status = CELIX_ILLEGAL_ARGUMENT;
+ } else {
+ *symbolicName = module->description;
+ }
+ return status;
+}
+
char * module_getId(module_pt module) {
return module->id;
}
@@ -278,11 +319,4 @@ array_list_pt module_getDependents(module_pt module) {
arrayList_addAll(dependents, module->dependentImporters);
return dependents;
-}
-
-celix_status_t module_getGroup(module_pt module, const char **group) {
- if (group != NULL) {
- *group = module->group;
- }
- return CELIX_SUCCESS;
}
\ No newline at end of file
diff --git a/libs/framework/src/service_registry.c b/libs/framework/src/service_registry.c
index 876965c..626dc57 100644
--- a/libs/framework/src/service_registry.c
+++ b/libs/framework/src/service_registry.c
@@ -191,10 +191,9 @@ static celix_status_t serviceRegistry_registerServiceInternal(service_registry_p
array_list_pt regs;
long svcId = reservedId > 0 ? reservedId : celix_serviceRegistry_nextSvcId(registry);
- celix_properties_setLong(dictionary, CELIX_FRAMEWORK_SERVICE_BUNDLE_ID, celix_bundle_getId(bundle));
+ celix_properties_setLong(dictionary, CELIX_FRAMEWORK_SERVICE_BUNDLE_ID, celix_bundle_getId(bundle));
-
- if (svcType == CELIX_DEPRECATED_FACTORY_SERVICE) {
+ if (svcType == CELIX_DEPRECATED_FACTORY_SERVICE) {
celix_properties_set(dictionary, CELIX_FRAMEWORK_SERVICE_SCOPE, CELIX_FRAMEWORK_SERVICE_SCOPE_BUNDLE);
*registration = serviceRegistration_createServiceFactory(registry->callback, bundle, serviceName,
svcId, serviceObject,
diff --git a/libs/framework/src/service_tracker.c b/libs/framework/src/service_tracker.c
index b8e4b0c..344052b 100644
--- a/libs/framework/src/service_tracker.c
+++ b/libs/framework/src/service_tracker.c
@@ -49,6 +49,8 @@ static inline celix_tracked_entry_t* tracked_create(service_reference_pt ref, vo
celix_tracked_entry_t *tracked = calloc(1, sizeof(*tracked));
tracked->reference = ref;
tracked->service = svc;
+ tracked->serviceId = celix_properties_getAsLong(props, CELIX_FRAMEWORK_SERVICE_ID, -1);
+ tracked->serviceRanking = celix_properties_getAsLong(props, CELIX_FRAMEWORK_SERVICE_RANKING, 0);
tracked->properties = props;
tracked->serviceOwner = bnd;
tracked->serviceName = celix_properties_get(props, OSGI_FRAMEWORK_OBJECTCLASS, "Error");
@@ -437,7 +439,10 @@ static celix_status_t serviceTracker_track(service_tracker_t* tracker, service_r
arrayList_add(tracker->trackedServices, tracked);
celixThreadMutex_unlock(&tracker->mutex);
- celix_serviceTracker_useHighestRankingService(tracker, tracked->serviceName, tracker, NULL, NULL, serviceTracker_checkAndInvokeSetService);
+ if (tracker->set != NULL || tracker->setWithProperties != NULL || tracker->setWithOwner != NULL) {
+ celix_serviceTracker_useHighestRankingService(tracker, tracked->serviceName, tracker, NULL, NULL,
+ serviceTracker_checkAndInvokeSetService);
+ }
serviceTracker_invokeAddService(tracker, tracked);
}
} else {
@@ -718,7 +723,6 @@ bool celix_serviceTracker_useHighestRankingService(service_tracker_t *tracker,
bool called = false;
celix_tracked_entry_t *tracked = NULL;
celix_tracked_entry_t *highest = NULL;
- long highestRank = 0;
unsigned int i;
//first lock tracker and get highest tracked entry
@@ -727,11 +731,17 @@ bool celix_serviceTracker_useHighestRankingService(service_tracker_t *tracker,
for (i = 0; i < size; i++) {
tracked = (celix_tracked_entry_t *) arrayList_get(tracker->trackedServices, i);
- if (serviceName != NULL && tracked->serviceName != NULL && strncmp(tracked->serviceName, serviceName, 10*1024) == 0) {
- const char *val = properties_getWithDefault(tracked->properties, OSGI_FRAMEWORK_SERVICE_RANKING, "0");
- long rank = strtol(val, NULL, 10);
- if (highest == NULL || rank > highestRank) {
+ if (serviceName != NULL && tracked->serviceName != NULL && celix_utils_stringEquals(tracked->serviceName, serviceName)) {
+ if (highest == NULL) {
highest = tracked;
+ } else {
+ int compare = celix_utils_compareServiceIdsAndRanking(
+ tracked->serviceId, tracked->serviceRanking,
+ highest->serviceId, highest->serviceRanking
+ );
+ if (compare < 0) {
+ highest = tracked;
+ }
}
}
}
diff --git a/libs/framework/src/service_tracker_private.h b/libs/framework/src/service_tracker_private.h
index 9580b23..49e9689 100644
--- a/libs/framework/src/service_tracker_private.h
+++ b/libs/framework/src/service_tracker_private.h
@@ -74,6 +74,8 @@ struct celix_serviceTracker {
typedef struct celix_tracked_entry {
service_reference_pt reference;
void *service;
+ long serviceId; //cached service.id of the service
+ long serviceRanking; //cached service.ranking of the service
const char *serviceName;
properties_t *properties;
bundle_t *serviceOwner;
diff --git a/libs/promises/api/celix/impl/SharedPromiseState.h b/libs/promises/api/celix/impl/SharedPromiseState.h
index f92fa05..ec3f68a 100644
--- a/libs/promises/api/celix/impl/SharedPromiseState.h
+++ b/libs/promises/api/celix/impl/SharedPromiseState.h
@@ -892,7 +892,7 @@ void celix::impl::SharedPromiseState<T>::addOnFailureConsumeCallback(std::functi
} catch (const std::exception &e) {
callback(e);
} catch (...) {
- //NOTE not an exception based on std::exception, "repacking" it to logical error
+ //NOTE not a exception based on std::exception, "repacking" it to logical error
std::logic_error logicError{"Unknown exception throw for the failure of A celix::Promise"};
callback(logicError);
}
@@ -909,7 +909,7 @@ inline void celix::impl::SharedPromiseState<void>::addOnFailureConsumeCallback(s
} catch (const std::exception &e) {
callback(e);
} catch (...) {
- //NOTE not an exception based on std::exception, "repacking" it to logical error
+ //NOTE not a exception based on std::exception, "repacking" it to logical error
std::logic_error logicError{"Unknown exception throw for the failure of A celix::Promise"};
callback(logicError);
}
diff --git a/libs/utils/gtest/CMakeLists.txt b/libs/utils/gtest/CMakeLists.txt
index 8111df3..6cb860d 100644
--- a/libs/utils/gtest/CMakeLists.txt
+++ b/libs/utils/gtest/CMakeLists.txt
@@ -21,6 +21,9 @@ add_executable(test_utils
src/VersionRangeTestSuite.cc
src/TimeUtilsTestSuite.cc
src/FileUtilsTestSuite.cc
+ src/CxxUtilsTestSuite.cc
+ src/CxxPropertiesTestSuite.cc
+ src/CxxFilterTestSuite.cc
)
target_link_libraries(test_utils PRIVATE Celix::utils GTest::gtest GTest::gtest_main)
diff --git a/libs/framework/gtest/src/CxxFilterTestSuite.cc b/libs/utils/gtest/src/CxxFilterTestSuite.cc
similarity index 94%
rename from libs/framework/gtest/src/CxxFilterTestSuite.cc
rename to libs/utils/gtest/src/CxxFilterTestSuite.cc
index 4d70b2a..784a674 100644
--- a/libs/framework/gtest/src/CxxFilterTestSuite.cc
+++ b/libs/utils/gtest/src/CxxFilterTestSuite.cc
@@ -29,7 +29,7 @@ public:
TEST_F(CxxFilterTestSuite, CreateDestroy) {
celix::Filter filter{};
EXPECT_TRUE(filter.empty());
- EXPECT_TRUE(filter.getCFilter() == nullptr); //TODO tbd add support for empty filter to C?
+ EXPECT_TRUE(filter.getCFilter() == nullptr);
EXPECT_TRUE(filter.getFilterString().empty());
}
@@ -43,7 +43,7 @@ TEST_F(CxxFilterTestSuite, FilterString) {
}
TEST_F(CxxFilterTestSuite, InvalidFilter) {
- EXPECT_THROW(celix::Filter{"bla"}, celix::Exception);
+ EXPECT_THROW(celix::Filter{"bla"}, celix::FilterException);
}
TEST_F(CxxFilterTestSuite, EmptyFilterTest) {
diff --git a/libs/framework/gtest/src/CxxPropertiesTestSuite.cc b/libs/utils/gtest/src/CxxPropertiesTestSuite.cc
similarity index 90%
rename from libs/framework/gtest/src/CxxPropertiesTestSuite.cc
rename to libs/utils/gtest/src/CxxPropertiesTestSuite.cc
index 1c6651e..8f151e4 100644
--- a/libs/framework/gtest/src/CxxPropertiesTestSuite.cc
+++ b/libs/utils/gtest/src/CxxPropertiesTestSuite.cc
@@ -27,12 +27,12 @@ class CxxPropertiesTestSuite : public ::testing::Test {
public:
};
-TEST_F(CxxPropertiesTestSuite, CreateDestroy) {
+TEST_F(CxxPropertiesTestSuite, testCreateDestroy) {
celix::Properties props{};
EXPECT_EQ(0, props.size());
}
-TEST_F(CxxPropertiesTestSuite, FillAndLoop) {
+TEST_F(CxxPropertiesTestSuite, testFillAndLoop) {
celix::Properties props{};
EXPECT_EQ(0, props.size());
@@ -45,7 +45,6 @@ TEST_F(CxxPropertiesTestSuite, FillAndLoop) {
EXPECT_EQ(props.get("key1"), "value1");
EXPECT_EQ(props.get("key2"), "value2");
- //TODO ASSERT_THAT(props.get("key3"), MatchesRegex("3.3.*"));
EXPECT_EQ(props.getAsDouble("key3", 0), 3.3);
EXPECT_EQ(props.get("key4"), "4");
EXPECT_EQ(props.getAsLong("key4", -1), 4);
@@ -60,7 +59,7 @@ TEST_F(CxxPropertiesTestSuite, FillAndLoop) {
EXPECT_EQ(5, count);
}
-TEST_F(CxxPropertiesTestSuite, CopyTest) {
+TEST_F(CxxPropertiesTestSuite, testCopy) {
celix::Properties props{};
props["key1"] = "value1";
@@ -75,7 +74,7 @@ TEST_F(CxxPropertiesTestSuite, CopyTest) {
EXPECT_EQ(v2, "value1_new");
}
-TEST_F(CxxPropertiesTestSuite, WrapTest) {
+TEST_F(CxxPropertiesTestSuite, testWrap) {
auto *props = celix_properties_create();
celix_properties_set(props, "test", "test");
@@ -88,4 +87,4 @@ TEST_F(CxxPropertiesTestSuite, WrapTest) {
EXPECT_EQ(1, celix_properties_size(props));
celix_properties_destroy(props);
-}
+}
\ No newline at end of file
diff --git a/libs/utils/gtest/src/CxxUtilsTestSuite.cc b/libs/utils/gtest/src/CxxUtilsTestSuite.cc
new file mode 100644
index 0000000..b98a5b0
--- /dev/null
+++ b/libs/utils/gtest/src/CxxUtilsTestSuite.cc
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "celix/Utils.h"
+
+class CxxUtilsTestSuite : public ::testing::Test {
+public:
+};
+
+namespace example {
+ class TestType {
+ public:
+ std::string NAME; //dummy non-static NAME member, should not impact the typeName call
+ std::string VERSION; //dummy non-static VERSION member, should not impact the typeVersion call
+ };
+
+ class TestType2 {
+ public:
+ static constexpr std::string_view NAME = "AnotherTestTypeName";
+ static constexpr const char * const VERSION = "1.2.0";
+ };
+
+ class TestType3 {
+ public:
+ static constexpr int NAME = 4; //dummy static int, which should not be used as type name (cannot be used to construct a string)
+ static constexpr int VERSION = 1; //dummy static int, which should not be used as type name (cannot be used to construct a string)
+ };
+}
+
+
+TEST_F(CxxUtilsTestSuite, testTypeName) {
+ //When inferring a type name with no provided name and the type does not have a NAME static member,
+ //the call should return an inferred name based on __PRETTY__FUNCTION__ (see celix::impl::extractTypeName)
+ auto name = celix::typeName<example::TestType>();
+ EXPECT_FALSE(name.empty());
+
+ //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
+ name = celix::typeName<example::TestType2>();
+ EXPECT_EQ(std::string{name}, std::string{"AnotherTestTypeName"});
+
+ //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"});
+
+ //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.
+ name = celix::typeName<example::TestType2>("OverrideName");
+ EXPECT_EQ(name, std::string{"OverrideName"});
+
+ //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)
+ name = celix::typeName<example::TestType3>();
+ //note not testing what exactly is inferred (__PRETTY_FUNCTION__ can differ per platform)
+ EXPECT_NE(std::string{"4"}, name);
+}
+
+TEST_F(CxxUtilsTestSuite, testTypeVersion) {
+ //When inferring a type version with no provided version and the type does not have a VERSION static member,
+ //the call should return an empty version.
+ auto version = celix::typeVersion<example::TestType>();
+ EXPECT_TRUE(version.empty());
+
+ //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.
+ version = celix::typeVersion<example::TestType2>();
+ EXPECT_EQ(std::string{version}, std::string{"1.2.0"});
+
+ //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"});
+
+ //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.
+ version = celix::typeVersion<example::TestType2>("2.2.2");
+ EXPECT_EQ(version, std::string{"2.2.2"});
+}
+
+TEST_F(CxxUtilsTestSuite, testSplit) {
+ auto tokens = celix::split("item1,item2,item3");
+ ASSERT_EQ(tokens.size(), 3);
+ EXPECT_EQ(tokens[0], "item1");
+ EXPECT_EQ(tokens[1], "item2");
+ EXPECT_EQ(tokens[2], "item3");
+
+ tokens = celix::split(" item1 , item2 , item3 ");
+ ASSERT_EQ(tokens.size(), 3);
+ EXPECT_EQ(tokens[0], "item1");
+ EXPECT_EQ(tokens[1], "item2");
+ EXPECT_EQ(tokens[2], "item3");
+
+ tokens = celix::split(" item1 , ");
+ ASSERT_EQ(tokens.size(), 1);
+ EXPECT_EQ(tokens[0], "item1");
+
+ tokens = celix::split("");
+ EXPECT_EQ(tokens.size(), 0);
+
+ tokens = celix::split(" , , ");
+ EXPECT_EQ(tokens.size(), 0);
+}
\ No newline at end of file
diff --git a/libs/framework/include/celix/Filter.h b/libs/utils/include/celix/Filter.h
similarity index 78%
rename from libs/framework/include/celix/Filter.h
rename to libs/utils/include/celix/Filter.h
index bb904cd..1157b91 100644
--- a/libs/framework/include/celix/Filter.h
+++ b/libs/utils/include/celix/Filter.h
@@ -23,11 +23,29 @@
#include "celix_filter.h"
#include "celix/Properties.h"
-#include "celix/Exception.h"
namespace celix {
/**
+ * @brief FilterException
+ */
+ class FilterException : public std::exception {
+ public:
+ explicit FilterException(std::string msg) : w{std::move(msg)} {}
+
+ FilterException(const FilterException&) = default;
+ FilterException(FilterException&&) = default;
+ FilterException& operator=(const FilterException&) = default;
+ FilterException& operator=(FilterException&&) = default;
+
+ [[nodiscard]] const char* what() const noexcept override {
+ return w.c_str();
+ }
+ private:
+ std::string w;
+ };
+
+ /**
* @brief An RFC 1960-based (LDAP) Filter.
*
* Some examples:
@@ -65,7 +83,7 @@ namespace celix {
/**
* @brief Gets the filter string
*/
- std::string getFilterString() const {
+ [[nodiscard]] std::string getFilterString() const {
auto cStr = getFilterCString();
return cStr == nullptr ? std::string{} : std::string{cStr};
}
@@ -73,14 +91,14 @@ namespace celix {
/**
* @brief Get the C string. valid as long as the filter object is valid.
*/
- const char* getFilterCString() const {
+ [[nodiscard]] const char* getFilterCString() const {
return celix_filter_getFilterString(cFilter.get());
}
/**
* @brief match the filter against the provided properties
*/
- bool match(const celix::Properties& properties) const {
+ [[nodiscard]] bool match(const celix::Properties& properties) const {
return celix_filter_match(cFilter.get(), properties.getCProperties());
}
@@ -88,7 +106,7 @@ 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.
*/
- std::string findAttribute(const std::string& attributeKey) const {
+ [[nodiscard]] std::string findAttribute(const std::string& attributeKey) const {
auto* cValue = celix_filter_findAttribute(cFilter.get(), attributeKey.c_str());
return cValue == nullptr ? std::string{} : std::string{cValue};
}
@@ -96,7 +114,7 @@ namespace celix {
/**
* @brief Check whether the filter has a attribute with the provided attribute key.
*/
- bool hasAttribute(const std::string& attributeKey) const {
+ [[nodiscard]] bool hasAttribute(const std::string& attributeKey) const {
return celix_filter_findAttribute(cFilter.get(), attributeKey.c_str()) != nullptr;
}
@@ -106,14 +124,14 @@ namespace celix {
* @warning Try not the depend on the C API from a C++ bundle. If features are missing these should be added to
* the C++ API.
*/
- celix_filter_t* getCFilter() const {
+ [[nodiscard]] celix_filter_t* getCFilter() const {
return cFilter.get();
}
/**
* @brief Return whether the filter is empty.
*/
- bool empty() const {
+ [[nodiscard]] bool empty() const {
return cFilter == nullptr;
}
private:
@@ -123,7 +141,7 @@ namespace celix {
}
auto* cf = celix_filter_create(filterStr.c_str());
if (cf == nullptr) {
- throw celix::Exception{"Invalid LDAP filter '" + filterStr + "'"};
+ throw celix::FilterException{"Invalid LDAP filter '" + filterStr + "'"};
}
return std::shared_ptr<celix_filter_t>{cf, [](celix_filter_t *f) {
celix_filter_destroy(f);
diff --git a/libs/framework/include/celix/Properties.h b/libs/utils/include/celix/Properties.h
similarity index 89%
rename from libs/framework/include/celix/Properties.h
rename to libs/utils/include/celix/Properties.h
index 0c7eaa0..7698e77 100644
--- a/libs/framework/include/celix/Properties.h
+++ b/libs/utils/include/celix/Properties.h
@@ -38,6 +38,7 @@ namespace celix {
iter = hashMapIterator_construct((hash_map_t*)props);
next();
}
+
explicit PropertiesIterator(const celix_properties_t* props) {
iter = hashMapIterator_construct((hash_map_t*)props);
next();
@@ -108,7 +109,7 @@ namespace celix {
return *this;
}
- const char* getValue() const {
+ [[nodiscard]] const char* getValue() const {
return celix_properties_get(props.get(), key.c_str(), nullptr);
}
@@ -157,7 +158,7 @@ namespace celix {
* @warning Try not the depend on the C API from a C++ bundle. If features are missing these should be added to
* the C++ API.
*/
- celix_properties_t* getCProperties() const {
+ [[nodiscard]] celix_properties_t* getCProperties() const {
return cProps.get();
}
@@ -169,16 +170,23 @@ namespace celix {
}
/**
+ * @brief Get the value for a property key
+ */
+ ValueRef operator[](std::string key) const {
+ return ValueRef{cProps, std::move(key)};
+ }
+
+ /**
* @brief begin iterator
*/
- const_iterator begin() const noexcept {
+ [[nodiscard]] const_iterator begin() const noexcept {
return PropertiesIterator{cProps.get()};
}
/**
* @brief end iterator
*/
- const_iterator end() const noexcept {
+ [[nodiscard]] const_iterator end() const noexcept {
auto iter = PropertiesIterator{cProps.get()};
iter.moveToEnd();
return iter;
@@ -187,14 +195,14 @@ namespace celix {
/**
* @brief constant begin iterator
*/
- const_iterator cbegin() const noexcept {
+ [[nodiscard]] const_iterator cbegin() const noexcept {
return PropertiesIterator{cProps.get()};
}
/**
* @brief constant end iterator
*/
- const_iterator cend() const noexcept {
+ [[nodiscard]] const_iterator cend() const noexcept {
auto iter = PropertiesIterator{cProps.get()};
iter.moveToEnd();
return iter;
@@ -203,7 +211,7 @@ namespace celix {
/**
* @brief Get the value for a property key or return the defaultValue if the key does not exists.
*/
- std::string get(const std::string& key, const std::string& defaultValue = {}) const {
+ [[nodiscard]] std::string get(const std::string& key, const std::string& defaultValue = {}) const {
const char* found = celix_properties_get(cProps.get(), key.c_str(), nullptr);
return found == nullptr ? std::string{defaultValue} : std::string{found};
}
@@ -211,21 +219,21 @@ namespace celix {
/**
* @brief Get the value as long for a property key or return the defaultValue if the key does not exists.
*/
- long getAsLong(const std::string& key, long defaultValue) const {
+ [[nodiscard]] long getAsLong(const std::string& key, long defaultValue) const {
return celix_properties_getAsLong(cProps.get(), key.c_str(), defaultValue);
}
/**
* @brief Get the value as double for a property key or return the defaultValue if the key does not exists.
*/
- double getAsDouble(const std::string &key, double defaultValue) const {
+ [[nodiscard]] double getAsDouble(const std::string &key, double defaultValue) const {
return celix_properties_getAsDouble(cProps.get(), key.c_str(), defaultValue);
}
/**
* @brief Get the value as bool for a property key or return the defaultValue if the key does not exists.
*/
- bool getAsBool(const std::string &key, bool defaultValue) const {
+ [[nodiscard]] bool getAsBool(const std::string &key, bool defaultValue) const {
return celix_properties_getAsBool(cProps.get(), key.c_str(), defaultValue);
}
@@ -262,14 +270,14 @@ namespace celix {
/**
* @brief Returns the nr of properties.
*/
- std::size_t size() const {
+ [[nodiscard]] std::size_t size() const {
return celix_properties_size(cProps.get());
}
/**
* @brief Converts the properties a (new) std::string, std::string map.
*/
- std::map<std::string, std::string> convertToMap() const {
+ [[nodiscard]] std::map<std::string, std::string> convertToMap() const {
std::map<std::string, std::string> result{};
for (const auto& pair : *this) {
result[pair.first] = pair.second;
@@ -280,7 +288,7 @@ namespace celix {
/**
* @brief Converts the properties a (new) std::string, std::string unordered map.
*/
- std::unordered_map<std::string, std::string> convertToUnorderedMap() const {
+ [[nodiscard]] std::unordered_map<std::string, std::string> convertToUnorderedMap() const {
std::unordered_map<std::string, std::string> result{};
for (const auto& pair : *this) {
result[pair.first] = pair.second;
diff --git a/libs/utils/include/celix/Utils.h b/libs/utils/include/celix/Utils.h
new file mode 100644
index 0000000..205360d
--- /dev/null
+++ b/libs/utils/include/celix/Utils.h
@@ -0,0 +1,240 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#pragma once
+
+
+#include <string>
+#include <cstring>
+#include <iostream>
+#include <vector>
+
+//NOTE based on has_rtti.cpp
+#if defined(__clang__)
+#if __has_feature(cxx_rtti)
+#define CELIX_RTTI_ENABLED
+#endif
+#elif defined(__GNUG__)
+#if defined(__GXX_RTTI)
+#define CELIX_RTTI_ENABLED
+#endif
+#elif defined(_MSC_VER)
+#if defined(_CPPRTTI)
+#define CELIX_RTTI_ENABLED
+#endif
+#endif
+
+//FORCE DISABLE RTTI
+//TODO #323 add test CI job to test rtti based type name infer
+#undef CELIX_RTTI_ENABLED
+
+#ifdef CELIX_RTTI_ENABLED
+#include <cxxabi.h>
+#endif
+
+namespace celix {
+namespace impl {
+
+ template<typename INTERFACE_TYPENAME>
+ std::string extractTypeName() {
+ std::string result;
+#ifdef CELIX_RTTI_ENABLED
+ result = typeid(INTERFACE_TYPENAME).name();
+ int status = 0;
+ char* demangled_name {abi::__cxa_demangle(result.c_str(), NULL, NULL, &status)};
+ if(status == 0) {
+ result = std::string{demangled_name};
+ free(demangled_name);
+ }
+#else
+ const char *templateStr = "INTERFACE_TYPENAME = ";
+ const size_t templateStrLen = strlen(templateStr);
+
+ result = __PRETTY_FUNCTION__; //USING pretty function to retrieve the filled in template argument without using typeid()
+ size_t bpos = result.find(templateStr) + templateStrLen; //find begin pos after INTERFACE_TYPENAME = entry
+ size_t epos = bpos;
+ while (isalnum(result[epos]) || result[epos] == '_' || result[epos] == ':') {
+ epos += 1;
+ }
+ size_t len = epos - bpos;
+ result = result.substr(bpos, len);
+#endif
+ if (result.empty()) {
+ std::cerr << "Cannot infer type name in function call '" << __PRETTY_FUNCTION__ << "'\n'";
+ }
+ return result;
+ }
+}
+}
+
+#if __cplusplus >= 201703L //C++17 or higher
+namespace celix::impl {
+
+ template<typename T>
+ constexpr typename std::enable_if_t<std::is_constructible_v<std::string, T>, bool>
+ canBeConstructedWithString() { return true; }
+
+ template<typename T>
+ constexpr typename std::enable_if_t<not std::is_constructible_v<std::string, T>, bool>
+ canBeConstructedWithString() { return false; }
+
+ template<typename T>
+ constexpr typename std::enable_if_t<std::is_member_object_pointer_v<decltype(&T::NAME)>, bool>
+ isNameMemberStatic() { return false; }
+
+ template<typename T>
+ constexpr typename std::enable_if_t<!std::is_member_object_pointer_v<decltype(&T::NAME)>, bool>
+ isNameMemberStatic() { return canBeConstructedWithString<decltype(T::NAME)>(); }
+
+ template<typename, typename = void>
+ constexpr bool hasStaticMemberName = false;
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-value"
+ /**
+ * Partial specialization only possible (and chosen) when late binding of decltype succeeds ->
+ * i.e. when T::NAME exists.
+ * note T::NAME is unused, so suppressing unused-value warning
+ */
+ template<typename T>
+ constexpr bool hasStaticMemberName<T, decltype(T::NAME,void())> = isNameMemberStatic<T>();
+#pragma GCC diagnostic pop
+
+ template<typename T>
+ constexpr typename std::enable_if_t<std::is_member_object_pointer_v<decltype(&T::VERSION)>, bool>
+ isVersionMemberStatic() { return false; }
+
+ template<typename T>
+ constexpr typename std::enable_if_t<not std::is_member_object_pointer_v<decltype(&T::VERSION)>, bool>
+ isVersionMemberStatic() { return canBeConstructedWithString<decltype(T::VERSION)>(); }
+
+ template<typename, typename = void>
+ constexpr bool hasStaticMemberVersion = false;
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-value"
+ /**
+ * Partial specialization only possible (and chosen) when late binding of decltype succeeds ->
+ * i.e. when T::VERSION exists.
+ * note T::VERSION is unused, so suppressing unused-value warning
+ */
+ template<typename T>
+ constexpr bool hasStaticMemberVersion<T, decltype(T::VERSION,void())> = isVersionMemberStatic<T>();
+#pragma GCC diagnostic pop
+}
+
+namespace celix {
+ /**
+ * @brief Returns the inferred type name for the template I if the providedTypeName is empty.
+ *
+ * If the a non empty providedTypeName is provided this will be returned.
+ * If the provideTypeName is empty and a static constexpr and accessible member I::NAME exists,
+ * that will be returned.
+ * Otherwise the celix::impl::typeName will be used to infer the type name.
+ * celix::impl::typeName uses the macro __PRETTY_FUNCTION__ to extract a type name.
+ */
+ template<typename I>
+ std::string typeName(const std::string& providedTypeName = "") {
+ if (!providedTypeName.empty()) {
+ return providedTypeName;
+ } else if constexpr (celix::impl::hasStaticMemberName<I>) {
+ return std::string{I::NAME};
+ } else {
+ return celix::impl::extractTypeName<I>();
+ }
+ }
+
+ /**
+ * @brief Returns the inferred type version for the template I if the providedVersion is empty.
+ *
+ * If the a non empty providedVersion is provided this will be returned.
+ * If the providedVersion is empty and a static constexpr and accessible member I::VERSION exists,
+ * that will be returned.
+ * Otherwise a empty string will be returned.
+ */
+ template<typename I>
+ std::string typeVersion(const std::string& providedVersion = "") {
+ if (!providedVersion.empty()) {
+ return providedVersion;
+ } else if constexpr (celix::impl::hasStaticMemberVersion<I>) {
+ return std::string{I::VERSION};
+ } else {
+ 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(const std::string& str, const std::string& delimiter = ",") {
+ std::vector<std::string> result{};
+ std::string delimiters = 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(", ", found);
+ result.emplace_back(str.substr(found, pos - found));
+ }
+ return result;
+ }
+}
+
+#else //Assuming at least C++11
+
+namespace celix {
+ /**
+ * @brief Returns the inferred type name for the template I if the providedTypeName is empty.
+ *
+ * If the a non empty providedTypeName is provided this will be returned.
+ * Otherwise the celix::impl::typeName will be used to infer the type name.
+ * celix::impl::typeName uses the macro __PRETTY_FUNCTION__ to extract a type name.
+ */
+ template<typename I>
+ std::string typeName(const std::string &providedTypeName = "") {
+ if (!providedTypeName.empty()) {
+ return providedTypeName;
+ } else {
+ return celix::impl::extractTypeName<I>();
+ }
+ }
+
+ /**
+ * @brief Returns the type version.
+ *
+ * Returns the provideVersion if not empty or an empty string.
+ * Note that this function does not do anything, but is signature
+ * compatible with the C++17 celix::typeName<I>() version.
+ */
+ template<typename I>
+ std::string typeVersion(const std::string& providedVersion = "") {
+ if (!providedVersion.empty()) {
+ return providedVersion;
+ } else {
+ return "";
+ }
+ }
+}
+
+#endif
+
+#undef CELIX_RTTI_ENABLED
\ No newline at end of file