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/01/03 20:10:24 UTC
[celix] 01/01: Adds initial impl for the C++ headers only wrappers
This is an automated email from the ASF dual-hosted git repository.
pnoltes pushed a commit to branch feature/cxx_headers
in repository https://gitbox.apache.org/repos/asf/celix.git
commit 0b0e894de92aa7a4d7252c30be4b47d6957c9a34
Author: Pepijn Noltes <pe...@gmail.com>
AuthorDate: Fri Nov 20 19:17:55 2020 +0100
Adds initial impl for the C++ headers only wrappers
---
.../http_admin/test/test/http_websocket_tests.cc | 1 +
.../log_service_v2/src/log_service_activator.c | 2 -
bundles/shell/shell/src/activator.c | 1 -
.../getting_started/creating_a_simple_bundle.md | 28 +-
examples/celix-examples/CMakeLists.txt | 2 +
.../dm_example_cxx/phase1/src/Phase1Activator.cc | 2 +-
.../dm_example_cxx/phase2/src/Phase2aActivator.cc | 2 +-
.../dm_example_cxx/phase2/src/Phase2bActivator.cc | 3 +-
.../dm_example_cxx/phase3/src/Phase3Activator.cc | 2 +-
.../phase3_locking/src/Phase3LockingActivator.cc | 2 +-
.../hello_world_cxx/src/BundleActivator.cc | 14 +-
.../services_example_cxx/CMakeLists.txt | 38 +-
.../celix-examples/services_example_cxx/README.md | 22 +
.../services_example_cxx/api/examples/ICalc.h | 13 +-
.../src/DynamicConsumerBundleActivator.cc | 152 ++++++
.../src/SimpleConsumerBundleActivator.cc | 90 ++++
.../src/SimpleProviderBundleActivator.cc | 55 ++
.../CMakeLists.txt | 0
.../api/IAnotherExample.h | 0
.../api/example.h | 0
.../bar/CMakeLists.txt | 0
.../bar/src/Bar.cc | 0
.../bar/src/Bar.h | 0
.../bar/src/BarActivator.cc | 2 +-
.../bar/src/BarActivator.h | 0
.../baz/CMakeLists.txt | 0
.../baz/src/Baz.cc | 0
.../baz/src/Baz.h | 0
.../baz/src/BazActivator.cc | 2 +-
.../baz/src/BazActivator.h | 0
.../foo/CMakeLists.txt | 0
.../foo/src/Foo.cc | 0
.../foo/src/Foo.h | 0
.../foo/src/FooActivator.cc | 2 +-
.../foo/src/FooActivator.h | 0
libs/framework/gtest/CMakeLists.txt | 9 +-
.../framework/gtest/src/CxxBundleContext_tests.cpp | 435 +++++++++++++++
libs/framework/gtest/src/CxxFilter_tests.cpp | 75 +++
libs/framework/gtest/src/CxxProperties_tests.cpp | 91 ++++
.../gtest/src/DependencyManagerTestSuite.cc | 3 +-
.../src/HelloWorldCxxActivator.cpp} | 16 +-
.../gtest/src/bundle_context_services_test.cpp | 28 +-
libs/framework/include/celix/Builders.h | 600 +++++++++++++++++++++
.../framework/include/celix/Bundle.h | 40 +-
libs/framework/include/celix/BundleActivator.h | 105 ++++
libs/framework/include/celix/BundleContext.h | 505 +++++++++++++++++
libs/framework/include/celix/Constants.h | 40 ++
libs/framework/include/celix/Filter.h | 91 ++++
.../framework/include/celix/Framework.h | 47 +-
libs/framework/include/celix/Properties.h | 217 ++++++++
.../celix/{dm/Properties.h => ServiceFactory.h} | 19 +-
libs/framework/include/celix/ServiceRegistration.h | 176 ++++++
libs/framework/include/celix/Trackers.h | 481 +++++++++++++++++
.../include/celix/{dm/types.h => Utils.h} | 37 +-
libs/framework/include/celix/dm/Component.h | 16 +-
libs/framework/include/celix/dm/Component_Impl.h | 13 -
.../framework/include/celix/dm/DependencyManager.h | 1 -
.../include/celix/dm/DependencyManager_Impl.h | 1 -
libs/framework/include/celix/dm/Properties.h | 5 +-
libs/framework/include/celix/dm/ProvidedService.h | 1 -
.../include/celix/dm/ProvidedService_Impl.h | 2 -
.../framework/include/celix/dm/ServiceDependency.h | 15 +-
.../include/celix/dm/ServiceDependency_Impl.h | 45 +-
libs/framework/include/celix/dm/types.h | 43 +-
libs/framework/include/celix_api.h | 4 +-
libs/framework/include/celix_bundle_activator.h | 68 ---
libs/framework/include/celix_bundle_context.h | 21 +-
libs/framework/include/celix_constants.h | 72 ++-
libs/framework/include/celix_log.h | 2 +
libs/framework/include/dm_component.h | 3 +-
libs/framework/include/service_registry.h | 4 +-
libs/framework/src/bundle_context.c | 19 +-
libs/framework/src/celix_log.c | 6 +-
libs/framework/src/dm_component_impl.c | 11 +-
libs/framework/src/dm_service_dependency.c | 17 -
libs/framework/src/service_registry.c | 33 +-
libs/framework/src/service_tracker.c | 2 +-
libs/utils/src/filter.c | 2 +-
libs/utils/src/properties.c | 2 +-
79 files changed, 3416 insertions(+), 442 deletions(-)
diff --git a/bundles/http_admin/test/test/http_websocket_tests.cc b/bundles/http_admin/test/test/http_websocket_tests.cc
index 9ea73ea..1db9f74 100644
--- a/bundles/http_admin/test/test/http_websocket_tests.cc
+++ b/bundles/http_admin/test/test/http_websocket_tests.cc
@@ -27,6 +27,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
+#include <string.h>
#include "celix_api.h"
#include "http_admin/api.h"
diff --git a/bundles/logging/log_service_v2/src/log_service_activator.c b/bundles/logging/log_service_v2/src/log_service_activator.c
index c3cf9f9..6570218 100644
--- a/bundles/logging/log_service_v2/src/log_service_activator.c
+++ b/bundles/logging/log_service_v2/src/log_service_activator.c
@@ -109,7 +109,6 @@ celix_status_t bundleActivator_start(void * userData, celix_bundle_context_t *co
logFactory_create(activator->logger, &activator->factory);
celix_properties_t *props = celix_properties_create();
- celix_properties_set(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, CELIX_FRAMEWORK_SERVICE_C_LANGUAGE);
bundleContext_registerServiceFactory(context, (char *) OSGI_LOGSERVICE_NAME, activator->factory, props, &activator->logServiceFactoryReg);
@@ -124,7 +123,6 @@ celix_status_t bundleActivator_start(void * userData, celix_bundle_context_t *co
activator->reader_service->removeAllLogListener = logReaderService_removeAllLogListener;
props = celix_properties_create();
- celix_properties_set(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, CELIX_FRAMEWORK_SERVICE_C_LANGUAGE);
bundleContext_registerService(context, (char *) OSGI_LOGSERVICE_READER_SERVICE_NAME, activator->reader_service, props, &activator->logReaderServiceReg);
return status;
diff --git a/bundles/shell/shell/src/activator.c b/bundles/shell/shell/src/activator.c
index b33667e..8675423 100644
--- a/bundles/shell/shell/src/activator.c
+++ b/bundles/shell/shell/src/activator.c
@@ -173,7 +173,6 @@ celix_status_t bundleActivator_create(celix_bundle_context_t* ctx, void **_pptr)
celix_properties_set(activator->std_commands[i].props, CELIX_SHELL_COMMAND_NAME, activator->std_commands[i].name);
celix_properties_set(activator->std_commands[i].props, CELIX_SHELL_COMMAND_USAGE, activator->std_commands[i].usage);
celix_properties_set(activator->std_commands[i].props, CELIX_SHELL_COMMAND_DESCRIPTION, activator->std_commands[i].description);
- celix_properties_set(activator->std_commands[i].props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, CELIX_FRAMEWORK_SERVICE_C_LANGUAGE);
activator->std_commands[i].service.handle = ctx;
activator->std_commands[i].service.executeCommand = activator->std_commands[i].exec;
diff --git a/documents/getting_started/creating_a_simple_bundle.md b/documents/getting_started/creating_a_simple_bundle.md
index 56375b4..b992e36 100644
--- a/documents/getting_started/creating_a_simple_bundle.md
+++ b/documents/getting_started/creating_a_simple_bundle.md
@@ -165,25 +165,21 @@ The C++ Bundle Activator:
#include <memory>
#include <iostream>
-#include <celix_api.h>
+#include "celix/BundleActivator.h"
namespace /*anon*/ {
- class BundleActivator {
- public:
- BundleActivator(std::shared_ptr<celix::dm::DependencyManager> _mng) : mng{_mng} {
- std::cout << "Hello world from C++ bundle with id " << bndId() << std::endl;
- }
- ~BundleActivator() {
- std::cout << "Goodbye world from C++ bundle with id " << bndId() << std::endl;
- }
- private:
- long bndId() const {
- return celix_bundle_getId(celix_bundleContext_getBundle(mng->bundleContext()));
- }
-
- std::shared_ptr<celix::dm::DependencyManager> mng;
- };
+ class BundleActivator {
+ public:
+ explicit BundleActivator(std::shared_ptr<celix::BundleContext> _ctx) : ctx{std::move(_ctx)} {
+ std::cout << "Hello world from C++ bundle with id " << ctx->getBundle().getId() << std::endl;
+ }
+ ~BundleActivator() {
+ std::cout << "Goodbye world from C++ bundle with id " << ctx->getBundle().getId() << std::endl;
+ }
+ private:
+ const std::shared_ptr<celix::BundleContext> ctx;
+ };
}
diff --git a/examples/celix-examples/CMakeLists.txt b/examples/celix-examples/CMakeLists.txt
index 7e06819..b25a139 100644
--- a/examples/celix-examples/CMakeLists.txt
+++ b/examples/celix-examples/CMakeLists.txt
@@ -32,6 +32,8 @@ if (EXAMPLES)
add_subdirectory(services_example_c)
add_subdirectory(services_example_cxx)
+ add_subdirectory(svc_depependency_example_cxx)
+
#TODO refactor export_import
#add_subdirectory(export_import)
diff --git a/examples/celix-examples/dm_example_cxx/phase1/src/Phase1Activator.cc b/examples/celix-examples/dm_example_cxx/phase1/src/Phase1Activator.cc
index 52ede08..8984b66 100644
--- a/examples/celix-examples/dm_example_cxx/phase1/src/Phase1Activator.cc
+++ b/examples/celix-examples/dm_example_cxx/phase1/src/Phase1Activator.cc
@@ -20,7 +20,7 @@
#include "Phase1Cmp.h"
#include "Phase1Activator.h"
#include "IPhase2.h"
-#include <celix_api.h>
+#include <celix/BundleActivator.h>
using namespace celix::dm;
diff --git a/examples/celix-examples/dm_example_cxx/phase2/src/Phase2aActivator.cc b/examples/celix-examples/dm_example_cxx/phase2/src/Phase2aActivator.cc
index 2d0b20f..b3bc429 100644
--- a/examples/celix-examples/dm_example_cxx/phase2/src/Phase2aActivator.cc
+++ b/examples/celix-examples/dm_example_cxx/phase2/src/Phase2aActivator.cc
@@ -18,7 +18,7 @@
*/
#include <IName.h>
-#include <celix_api.h>
+#include <celix/BundleActivator.h>
#include "Phase2Cmp.h"
#include "Phase2Activator.h"
#include "celix_log_service.h"
diff --git a/examples/celix-examples/dm_example_cxx/phase2/src/Phase2bActivator.cc b/examples/celix-examples/dm_example_cxx/phase2/src/Phase2bActivator.cc
index c64b9a8..7ac3bc2 100644
--- a/examples/celix-examples/dm_example_cxx/phase2/src/Phase2bActivator.cc
+++ b/examples/celix-examples/dm_example_cxx/phase2/src/Phase2bActivator.cc
@@ -20,7 +20,8 @@
#include "Phase2Cmp.h"
#include "Phase2Activator.h"
#include "celix_log_service.h"
-#include <celix_bundle_activator.h>
+#include <celix/BundleActivator.h>
+
using namespace celix::dm;
diff --git a/examples/celix-examples/dm_example_cxx/phase3/src/Phase3Activator.cc b/examples/celix-examples/dm_example_cxx/phase3/src/Phase3Activator.cc
index d6e67ca..3c3e0e3 100644
--- a/examples/celix-examples/dm_example_cxx/phase3/src/Phase3Activator.cc
+++ b/examples/celix-examples/dm_example_cxx/phase3/src/Phase3Activator.cc
@@ -20,7 +20,7 @@
#include "Phase3Cmp.h"
#include "Phase3Activator.h"
-#include <celix_api.h>
+#include <celix/BundleActivator.h>
using namespace celix::dm;
diff --git a/examples/celix-examples/dm_example_cxx/phase3_locking/src/Phase3LockingActivator.cc b/examples/celix-examples/dm_example_cxx/phase3_locking/src/Phase3LockingActivator.cc
index 23c98a9..7ae909e 100644
--- a/examples/celix-examples/dm_example_cxx/phase3_locking/src/Phase3LockingActivator.cc
+++ b/examples/celix-examples/dm_example_cxx/phase3_locking/src/Phase3LockingActivator.cc
@@ -22,7 +22,7 @@
#include "Phase3LockingActivator.h"
#include <memory>
-#include <celix_api.h>
+#include <celix/BundleActivator.h>
using namespace celix::dm;
diff --git a/examples/celix-examples/hello_world_cxx/src/BundleActivator.cc b/examples/celix-examples/hello_world_cxx/src/BundleActivator.cc
index 2921ba7..8606444 100644
--- a/examples/celix-examples/hello_world_cxx/src/BundleActivator.cc
+++ b/examples/celix-examples/hello_world_cxx/src/BundleActivator.cc
@@ -20,24 +20,20 @@
#include <memory>
#include <iostream>
-#include <celix_api.h>
+#include "celix/BundleActivator.h"
namespace /*anon*/ {
class BundleActivator {
public:
- BundleActivator(std::shared_ptr<celix::dm::DependencyManager> _mng) : mng{std::move(_mng)} {
- std::cout << "Hello world from C++ bundle with id " << bndId() << std::endl;
+ explicit BundleActivator(std::shared_ptr<celix::BundleContext> _ctx) : ctx{std::move(_ctx)} {
+ std::cout << "Hello world from C++ bundle with id " << ctx->getBundle().getId() << std::endl;
}
~BundleActivator() {
- std::cout << "Goodbye world from C++ bundle with id " << bndId() << std::endl;
+ std::cout << "Goodbye world from C++ bundle with id " << ctx->getBundle().getId() << std::endl;
}
private:
- long bndId() const {
- return celix_bundle_getId(celix_bundleContext_getBundle(mng->bundleContext()));
- }
-
- std::shared_ptr<celix::dm::DependencyManager> mng;
+ const std::shared_ptr<celix::BundleContext> ctx;
};
}
diff --git a/examples/celix-examples/services_example_cxx/CMakeLists.txt b/examples/celix-examples/services_example_cxx/CMakeLists.txt
index 3bf458a..c8709d9 100644
--- a/examples/celix-examples/services_example_cxx/CMakeLists.txt
+++ b/examples/celix-examples/services_example_cxx/CMakeLists.txt
@@ -5,9 +5,9 @@
# 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
@@ -15,23 +15,29 @@
# specific language governing permissions and limitations
# under the License.
-add_library(services_example_cxx_api INTERFACE)
-target_include_directories(services_example_cxx_api INTERFACE api)
+add_library(ServiceExamplesApi INTERFACE)
+target_include_directories(ServiceExamplesApi INTERFACE api)
-add_subdirectory(bar)
-add_subdirectory(foo)
-add_subdirectory(baz)
+add_celix_bundle(SimpleProvider SOURCES src/SimpleProviderBundleActivator.cc VERSION 1.0.0)
+target_link_libraries(SimpleProvider PRIVATE ServiceExamplesApi)
-add_celix_container(services_example_cxx
- GROUP services_example
- COPY
- BUNDLES
+add_celix_bundle(SimpleConsumer SOURCES src/SimpleConsumerBundleActivator.cc VERSION 1.0.0)
+target_link_libraries(SimpleConsumer PRIVATE ServiceExamplesApi)
+
+add_celix_container(SimpleServicesExample CXX BUNDLES
Celix::shell
Celix::shell_tui
- bar_cxx
- foo_cxx
- baz_cxx
- PROPERTIES
- example=value
+ SimpleProvider
+ SimpleConsumer
)
+
+add_celix_bundle(DynamicConsumer SOURCES src/DynamicConsumerBundleActivator.cc VERSION 1.0.0)
+target_link_libraries(DynamicConsumer PRIVATE ServiceExamplesApi)
+
+add_celix_container(DynamicServicesExample CXX BUNDLES
+ Celix::shell
+ Celix::shell_tui
+ SimpleProvider
+ DynamicConsumer
+)
\ No newline at end of file
diff --git a/examples/celix-examples/services_example_cxx/README.md b/examples/celix-examples/services_example_cxx/README.md
new file mode 100644
index 0000000..d0622c8
--- /dev/null
+++ b/examples/celix-examples/services_example_cxx/README.md
@@ -0,0 +1,22 @@
+---
+title: Services Example C++
+---
+
+<!--
+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.
+-->
+
+TODO
\ No newline at end of file
diff --git a/libs/framework/include/celix/dm/Properties.h b/examples/celix-examples/services_example_cxx/api/examples/ICalc.h
similarity index 85%
copy from libs/framework/include/celix/dm/Properties.h
copy to examples/celix-examples/services_example_cxx/api/examples/ICalc.h
index 5c33885..91dd7b7 100644
--- a/libs/framework/include/celix/dm/Properties.h
+++ b/examples/celix-examples/services_example_cxx/api/examples/ICalc.h
@@ -19,9 +19,12 @@
#pragma once
-#include <map>
-#include <string>
+namespace examples {
-namespace celix { namespace dm {
- using Properties = std::map<std::string, std::string>;
-}}
+ class ICalc {
+ public:
+ virtual ~ICalc() = default;
+ virtual int calc(int input) = 0;
+ };
+
+}
\ No newline at end of file
diff --git a/examples/celix-examples/services_example_cxx/src/DynamicConsumerBundleActivator.cc b/examples/celix-examples/services_example_cxx/src/DynamicConsumerBundleActivator.cc
new file mode 100644
index 0000000..086f4c7
--- /dev/null
+++ b/examples/celix-examples/services_example_cxx/src/DynamicConsumerBundleActivator.cc
@@ -0,0 +1,152 @@
+/*
+ * 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 <utility>
+
+#include "celix/BundleActivator.h"
+#include "examples/ICalc.h"
+
+namespace /*anon*/ {
+
+ class DynamicConsumer {
+ public:
+ explicit DynamicConsumer(int _id) : id{_id} {}
+
+ ~DynamicConsumer() {
+ active = false;
+ calcThread.join();
+ auto msg = std::string{"Destroying consumer nr "} + std::to_string(id) + "\n";
+ std::cout << msg;
+ }
+
+ void start() {
+ std::lock_guard<std::mutex> lck{mutex};
+ calcThread = std::thread{&DynamicConsumer::run, this};
+ }
+
+ void setCalc(std::shared_ptr<examples::ICalc> _calc) {
+ std::lock_guard<std::mutex> lck{mutex};
+ calc = std::move(_calc);
+ }
+ private:
+ void run() {
+ // std::unique_lock<std::mutex> lck{mutex, std::defer_lock};
+ int count = 1;
+ while (active) {
+// lck.lock();
+ auto localCalc = calc;
+// lck.unlock();
+
+ /*
+ * note it is safe to use the localCalc outside a mutex,
+ * because the shared_prt count will ensure the service cannot be unregistered while in use.
+ */
+ if (localCalc) {
+ auto msg = std::string{"Calc result for consumer nr "} + std::to_string(id) + " with input " + std::to_string(count) + " is " + std::to_string(localCalc->calc(count)) + "\n";
+ std::cout << msg;
+ } else {
+ auto msg = std::string{"Calc service not available for consumer nr "} + std::to_string(id) + "\n";
+ std::cout << msg;
+ }
+
+ //NOTE the sleep also keeps the localCalc shared_ptr activate and as result block the removal of the service
+ std::this_thread::sleep_for(std::chrono::seconds{2});
+
+ ++count;
+ }
+ }
+
+ const int id;
+ std::atomic<bool> active{true};
+ std::shared_ptr<examples::ICalc> calc{};
+
+ std::mutex mutex{}; //protects below
+ std::thread calcThread{};
+ };
+
+ class DynamicConsumerFactory {
+ public:
+ static constexpr std::size_t MAX_CONSUMERS = 5;
+
+ explicit DynamicConsumerFactory(std::shared_ptr<celix::BundleContext> _ctx) : ctx{std::move(_ctx)} {}
+
+ ~DynamicConsumerFactory() {
+ ctx->logInfo("Destroying DynamicConsumerFactory");
+ active = false;
+ factoryThread.join();
+ }
+
+
+ void start() {
+ std::lock_guard<std::mutex> lck{mutex};
+ factoryThread = std::thread{&DynamicConsumerFactory::run, this};
+ }
+
+ void run() {
+ std::unique_lock<std::mutex> lck{mutex, std::defer_lock};
+ int nextConsumerId = 1;
+ while (active) {
+ lck.lock();
+ if (consumers.size() < MAX_CONSUMERS) {
+ ctx->logInfo("Creating dynamic consumer nr %i", consumers.size());
+ auto consumer = std::make_shared<DynamicConsumer>(nextConsumerId++);
+ trackers.push_back(createTracker(ctx, consumer)); //NOTE is this possible after a move?
+ consumers.push_back(consumer);
+ consumer->start();
+ } else {
+ ctx->logInfo("Resetting all trackers and consumers");
+ trackers.clear();
+ ctx->logInfo("Done resetting trackers");
+ consumers.clear();
+ ctx->logInfo("Done resetting consumer");
+ }
+ lck.unlock();
+ std::this_thread::sleep_for(std::chrono::seconds{1});
+ }
+ }
+ private:
+ static std::shared_ptr<celix::GenericServiceTracker> createTracker(const std::shared_ptr<celix::BundleContext>& ctx, const std::shared_ptr<DynamicConsumer>& consumer) {
+ return ctx->trackServices<examples::ICalc>()
+ .addSetCallback([consumer](std::shared_ptr<examples::ICalc> svc) {
+ consumer->setCalc(std::move(svc));
+ })
+ .build();
+ }
+
+ const std::shared_ptr<celix::BundleContext> ctx;
+ std::atomic<bool> active{true};
+
+ std::mutex mutex{}; //protects below
+ std::thread factoryThread{};
+ std::vector<std::shared_ptr<DynamicConsumer>> consumers{};
+ std::vector<std::shared_ptr<celix::GenericServiceTracker>> trackers{};
+ };
+
+ class DynamicConsumerBundleActivator {
+ public:
+ explicit DynamicConsumerBundleActivator(const std::shared_ptr<celix::BundleContext>& ctx) : factory{ctx} {
+ factory.start();
+ }
+ private:
+ DynamicConsumerFactory factory;
+ };
+
+}
+
+CELIX_GEN_CXX_BUNDLE_ACTIVATOR(DynamicConsumerBundleActivator)
\ No newline at end of file
diff --git a/examples/celix-examples/services_example_cxx/src/SimpleConsumerBundleActivator.cc b/examples/celix-examples/services_example_cxx/src/SimpleConsumerBundleActivator.cc
new file mode 100644
index 0000000..713b287
--- /dev/null
+++ b/examples/celix-examples/services_example_cxx/src/SimpleConsumerBundleActivator.cc
@@ -0,0 +1,90 @@
+/*
+ * 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 "celix/BundleActivator.h"
+#include "examples/ICalc.h"
+
+namespace /*anon*/ {
+
+ class SimpleConsumer {
+ public:
+ ~SimpleConsumer() {
+ active = false;
+ calcThread.join();
+ }
+
+ void start() {
+ std::lock_guard<std::mutex> lck{mutex};
+ calcThread = std::thread{&SimpleConsumer::run, this};
+ }
+
+ void setCalc(std::shared_ptr<examples::ICalc> _calc) {
+ std::lock_guard<std::mutex> lck{mutex};
+ calc = std::move(_calc);
+ }
+ private:
+ void run() {
+ std::unique_lock<std::mutex> lck{mutex, std::defer_lock};
+ int count = 1;
+ while (active) {
+ lck.lock();
+ auto localCalc = calc;
+ lck.unlock();
+
+ /*
+ * note it is safe to use the localCalc outside a mutex,
+ * because the shared_prt count will ensure the service cannot be unregistered while in use.
+ */
+ if (localCalc) {
+ std::cout << "Calc result for input " << count << " is " << localCalc->calc(count) << std::endl;
+ } else {
+ std::cout << "Calc service not available!" << std::endl;
+ }
+ std::this_thread::sleep_for(std::chrono::seconds{2});
+ ++count;
+ }
+ }
+
+ std::atomic<bool> active{true};
+
+ std::mutex mutex{}; //protects below
+ std::shared_ptr<examples::ICalc> calc{};
+ std::thread calcThread{};
+ };
+
+ class SimpleConsumerBundleActivator {
+ public:
+ explicit SimpleConsumerBundleActivator(const std::shared_ptr<celix::BundleContext>& ctx) :
+ tracker{createTracker(ctx)} {
+ consumer.start();
+ }
+ private:
+ std::shared_ptr<celix::GenericServiceTracker> createTracker(const std::shared_ptr<celix::BundleContext>& ctx) {
+ return ctx->trackServices<examples::ICalc>()
+ .addSetCallback(std::bind(&SimpleConsumer::setCalc, &consumer, std::placeholders::_1))
+ .build();
+ }
+
+ const std::shared_ptr<celix::GenericServiceTracker> tracker;
+ SimpleConsumer consumer{};
+ };
+
+}
+
+CELIX_GEN_CXX_BUNDLE_ACTIVATOR(SimpleConsumerBundleActivator)
\ No newline at end of file
diff --git a/examples/celix-examples/services_example_cxx/src/SimpleProviderBundleActivator.cc b/examples/celix-examples/services_example_cxx/src/SimpleProviderBundleActivator.cc
new file mode 100644
index 0000000..efde6f2
--- /dev/null
+++ b/examples/celix-examples/services_example_cxx/src/SimpleProviderBundleActivator.cc
@@ -0,0 +1,55 @@
+/*
+ * 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 "celix/BundleActivator.h"
+#include "examples/ICalc.h"
+
+namespace /*anon*/ {
+
+ class Calc : public examples::ICalc {
+ public:
+ explicit Calc(int _seed) : seed{_seed} {}
+ ~Calc() override = default;
+
+ int calc(int input) override {
+ return seed * input;
+ }
+ private:
+ const int seed;
+ };
+
+ class SimpleProviderBundleActivator {
+ public:
+ explicit SimpleProviderBundleActivator(std::shared_ptr<celix::BundleContext> ctx) :
+ registration{createCalcService(ctx)} {}
+
+ private:
+ static std::shared_ptr<celix::ServiceRegistration> createCalcService(std::shared_ptr<celix::BundleContext>& ctx) {
+ int seed = 42;
+ return ctx->registerService<examples::ICalc>(std::make_shared<Calc>(seed))
+ .addProperty("seed", seed)
+ .build();
+ }
+
+ const std::shared_ptr<celix::ServiceRegistration> registration;
+ };
+
+}
+
+CELIX_GEN_CXX_BUNDLE_ACTIVATOR(SimpleProviderBundleActivator)
\ No newline at end of file
diff --git a/examples/celix-examples/services_example_cxx/CMakeLists.txt b/examples/celix-examples/svc_depependency_example_cxx/CMakeLists.txt
similarity index 100%
copy from examples/celix-examples/services_example_cxx/CMakeLists.txt
copy to examples/celix-examples/svc_depependency_example_cxx/CMakeLists.txt
diff --git a/examples/celix-examples/services_example_cxx/api/IAnotherExample.h b/examples/celix-examples/svc_depependency_example_cxx/api/IAnotherExample.h
similarity index 100%
rename from examples/celix-examples/services_example_cxx/api/IAnotherExample.h
rename to examples/celix-examples/svc_depependency_example_cxx/api/IAnotherExample.h
diff --git a/examples/celix-examples/services_example_cxx/api/example.h b/examples/celix-examples/svc_depependency_example_cxx/api/example.h
similarity index 100%
rename from examples/celix-examples/services_example_cxx/api/example.h
rename to examples/celix-examples/svc_depependency_example_cxx/api/example.h
diff --git a/examples/celix-examples/services_example_cxx/bar/CMakeLists.txt b/examples/celix-examples/svc_depependency_example_cxx/bar/CMakeLists.txt
similarity index 100%
rename from examples/celix-examples/services_example_cxx/bar/CMakeLists.txt
rename to examples/celix-examples/svc_depependency_example_cxx/bar/CMakeLists.txt
diff --git a/examples/celix-examples/services_example_cxx/bar/src/Bar.cc b/examples/celix-examples/svc_depependency_example_cxx/bar/src/Bar.cc
similarity index 100%
rename from examples/celix-examples/services_example_cxx/bar/src/Bar.cc
rename to examples/celix-examples/svc_depependency_example_cxx/bar/src/Bar.cc
diff --git a/examples/celix-examples/services_example_cxx/bar/src/Bar.h b/examples/celix-examples/svc_depependency_example_cxx/bar/src/Bar.h
similarity index 100%
rename from examples/celix-examples/services_example_cxx/bar/src/Bar.h
rename to examples/celix-examples/svc_depependency_example_cxx/bar/src/Bar.h
diff --git a/examples/celix-examples/services_example_cxx/bar/src/BarActivator.cc b/examples/celix-examples/svc_depependency_example_cxx/bar/src/BarActivator.cc
similarity index 95%
rename from examples/celix-examples/services_example_cxx/bar/src/BarActivator.cc
rename to examples/celix-examples/svc_depependency_example_cxx/bar/src/BarActivator.cc
index 0da8e29..9c26772 100644
--- a/examples/celix-examples/services_example_cxx/bar/src/BarActivator.cc
+++ b/examples/celix-examples/svc_depependency_example_cxx/bar/src/BarActivator.cc
@@ -17,7 +17,7 @@
* under the License.
*/
-#include <celix_api.h>
+#include <celix/BundleActivator.h>
#include "Bar.h"
#include "BarActivator.h"
diff --git a/examples/celix-examples/services_example_cxx/bar/src/BarActivator.h b/examples/celix-examples/svc_depependency_example_cxx/bar/src/BarActivator.h
similarity index 100%
rename from examples/celix-examples/services_example_cxx/bar/src/BarActivator.h
rename to examples/celix-examples/svc_depependency_example_cxx/bar/src/BarActivator.h
diff --git a/examples/celix-examples/services_example_cxx/baz/CMakeLists.txt b/examples/celix-examples/svc_depependency_example_cxx/baz/CMakeLists.txt
similarity index 100%
rename from examples/celix-examples/services_example_cxx/baz/CMakeLists.txt
rename to examples/celix-examples/svc_depependency_example_cxx/baz/CMakeLists.txt
diff --git a/examples/celix-examples/services_example_cxx/baz/src/Baz.cc b/examples/celix-examples/svc_depependency_example_cxx/baz/src/Baz.cc
similarity index 100%
rename from examples/celix-examples/services_example_cxx/baz/src/Baz.cc
rename to examples/celix-examples/svc_depependency_example_cxx/baz/src/Baz.cc
diff --git a/examples/celix-examples/services_example_cxx/baz/src/Baz.h b/examples/celix-examples/svc_depependency_example_cxx/baz/src/Baz.h
similarity index 100%
rename from examples/celix-examples/services_example_cxx/baz/src/Baz.h
rename to examples/celix-examples/svc_depependency_example_cxx/baz/src/Baz.h
diff --git a/examples/celix-examples/services_example_cxx/baz/src/BazActivator.cc b/examples/celix-examples/svc_depependency_example_cxx/baz/src/BazActivator.cc
similarity index 95%
rename from examples/celix-examples/services_example_cxx/baz/src/BazActivator.cc
rename to examples/celix-examples/svc_depependency_example_cxx/baz/src/BazActivator.cc
index 9813885..f38c469 100644
--- a/examples/celix-examples/services_example_cxx/baz/src/BazActivator.cc
+++ b/examples/celix-examples/svc_depependency_example_cxx/baz/src/BazActivator.cc
@@ -19,7 +19,7 @@
#include "Baz.h"
#include "BazActivator.h"
-#include <celix_api.h>
+#include <celix/BundleActivator.h>
using namespace celix::dm;
diff --git a/examples/celix-examples/services_example_cxx/baz/src/BazActivator.h b/examples/celix-examples/svc_depependency_example_cxx/baz/src/BazActivator.h
similarity index 100%
rename from examples/celix-examples/services_example_cxx/baz/src/BazActivator.h
rename to examples/celix-examples/svc_depependency_example_cxx/baz/src/BazActivator.h
diff --git a/examples/celix-examples/services_example_cxx/foo/CMakeLists.txt b/examples/celix-examples/svc_depependency_example_cxx/foo/CMakeLists.txt
similarity index 100%
rename from examples/celix-examples/services_example_cxx/foo/CMakeLists.txt
rename to examples/celix-examples/svc_depependency_example_cxx/foo/CMakeLists.txt
diff --git a/examples/celix-examples/services_example_cxx/foo/src/Foo.cc b/examples/celix-examples/svc_depependency_example_cxx/foo/src/Foo.cc
similarity index 100%
rename from examples/celix-examples/services_example_cxx/foo/src/Foo.cc
rename to examples/celix-examples/svc_depependency_example_cxx/foo/src/Foo.cc
diff --git a/examples/celix-examples/services_example_cxx/foo/src/Foo.h b/examples/celix-examples/svc_depependency_example_cxx/foo/src/Foo.h
similarity index 100%
rename from examples/celix-examples/services_example_cxx/foo/src/Foo.h
rename to examples/celix-examples/svc_depependency_example_cxx/foo/src/Foo.h
diff --git a/examples/celix-examples/services_example_cxx/foo/src/FooActivator.cc b/examples/celix-examples/svc_depependency_example_cxx/foo/src/FooActivator.cc
similarity index 94%
rename from examples/celix-examples/services_example_cxx/foo/src/FooActivator.cc
rename to examples/celix-examples/svc_depependency_example_cxx/foo/src/FooActivator.cc
index 50af21c..10dec88 100644
--- a/examples/celix-examples/services_example_cxx/foo/src/FooActivator.cc
+++ b/examples/celix-examples/svc_depependency_example_cxx/foo/src/FooActivator.cc
@@ -19,7 +19,7 @@
#include "Foo.h"
#include "FooActivator.h"
-#include <celix_api.h>
+#include <celix/BundleActivator.h>
using namespace celix::dm;
diff --git a/examples/celix-examples/services_example_cxx/foo/src/FooActivator.h b/examples/celix-examples/svc_depependency_example_cxx/foo/src/FooActivator.h
similarity index 100%
rename from examples/celix-examples/services_example_cxx/foo/src/FooActivator.h
rename to examples/celix-examples/svc_depependency_example_cxx/foo/src/FooActivator.h
diff --git a/libs/framework/gtest/CMakeLists.txt b/libs/framework/gtest/CMakeLists.txt
index 89f9eb0..4e06772 100644
--- a/libs/framework/gtest/CMakeLists.txt
+++ b/libs/framework/gtest/CMakeLists.txt
@@ -19,6 +19,7 @@ add_celix_bundle(simple_test_bundle1 NO_ACTIVATOR VERSION 1.0.0)
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)
+add_celix_bundle(simple_cxx_bundle SOURCES src/HelloWorldCxxActivator.cpp VERSION 1.0.0)
add_subdirectory(subdir) #simple_test_bundle4, simple_test_bundle5 and sublib
add_celix_bundle(unresolveable_bundle SOURCES src/nop_activator.c VERSION 1.0.0)
@@ -37,12 +38,17 @@ add_executable(test_framework
src/bundle_context_bundles_tests.cpp
src/bundle_context_services_test.cpp
src/DependencyManagerTestSuite.cc
+ src/CxxBundleContext_tests.cpp
+ src/CxxProperties_tests.cpp
+ src/HelloWorldCxxActivator.cpp
+ src/CxxFilter_tests.cpp
)
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)
+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)
target_include_directories(test_framework PRIVATE ../src)
+celix_get_bundle_file(simple_cxx_bundle SIMPLE_CXX_BUNDLE_LOC)
target_compile_definitions(test_framework PRIVATE
-DSIMPLE_TEST_BUNDLE1_LOCATION="$<TARGET_PROPERTY:simple_test_bundle1,BUNDLE_FILE>"
-DSIMPLE_TEST_BUNDLE2_LOCATION="$<TARGET_PROPERTY:simple_test_bundle2,BUNDLE_FILE>"
@@ -51,6 +57,7 @@ target_compile_definitions(test_framework PRIVATE
-DSIMPLE_TEST_BUNDLE5_LOCATION="$<TARGET_PROPERTY:simple_test_bundle5,BUNDLE_FILENAME>"
-DTEST_BUNDLE_WITH_EXCEPTION_LOCATION="$<TARGET_PROPERTY:bundle_with_exception,BUNDLE_FILE>"
-DTEST_BUNDLE_UNRESOLVEABLE_LOCATION="$<TARGET_PROPERTY:unresolveable_bundle,BUNDLE_FILE>"
+ -DSIMPLE_CXX_BUNDLE_LOC="${SIMPLE_CXX_BUNDLE_LOC}"
)
configure_file(config.properties.in config.properties @ONLY)
diff --git a/libs/framework/gtest/src/CxxBundleContext_tests.cpp b/libs/framework/gtest/src/CxxBundleContext_tests.cpp
new file mode 100644
index 0000000..60915b5
--- /dev/null
+++ b/libs/framework/gtest/src/CxxBundleContext_tests.cpp
@@ -0,0 +1,435 @@
+/*
+ * 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 <atomic>
+
+#include "celix/BundleContext.h"
+
+#include "celix_framework_factory.h"
+#include "celix_framework.h"
+
+class CxxBundleContextTestSuite : public ::testing::Test {
+public:
+ static constexpr const char * const TEST_BND1_LOC = "" SIMPLE_TEST_BUNDLE1_LOCATION "";
+ static constexpr const char * const TEST_BND2_LOC = "" SIMPLE_TEST_BUNDLE2_LOCATION "";
+
+ CxxBundleContextTestSuite() {
+ auto* properties = properties_create();
+ properties_set(properties, "LOGHELPER_ENABLE_STDOUT_FALLBACK", "true");
+ properties_set(properties, "org.osgi.framework.storage.clean", "onFirstInit");
+ properties_set(properties, "org.osgi.framework.storage", ".cacheCxxBundleContextTestFramework");
+
+ auto* cfw = celix_frameworkFactory_createFramework(properties);
+ fw = std::shared_ptr<celix_framework_t>{cfw, [](celix_framework_t* f){ celix_frameworkFactory_destroyFramework(f); }};
+ }
+
+ std::shared_ptr<celix_framework_t> fw{};
+};
+
+class TestInterface {
+
+};
+
+class TestImplementation : public TestInterface {
+
+};
+
+struct CInterface {
+ void *handle;
+ void (*hello)(void *handle);
+};
+
+TEST_F(CxxBundleContextTestSuite, RegisterServiceTest) {
+ auto* cCtx = celix_framework_getFrameworkContext(fw.get());
+ celix::BundleContext ctx{cCtx};
+
+ long svcId = celix_bundleContext_findService(cCtx, celix::typeName<TestInterface>().c_str());
+ EXPECT_EQ(svcId, -1L);
+
+ {
+ auto impl = std::make_shared<TestImplementation>();
+ auto svcReg = ctx.registerService<TestInterface>(impl).build();
+ svcReg->wait();
+ svcId = celix_bundleContext_findService(cCtx, celix::typeName<TestInterface>().c_str());
+ EXPECT_GE(svcId, 0L);
+ }
+
+ celix_bundleContext_waitForEvents(cCtx);
+ svcId = celix_bundleContext_findService(cCtx, celix::typeName<TestInterface>().c_str());
+ EXPECT_EQ(svcId, -1L);
+}
+
+TEST_F(CxxBundleContextTestSuite, RegisterCServiceTest) {
+ auto *cCtx = celix_framework_getFrameworkContext(fw.get());
+ celix::BundleContext ctx{cCtx};
+
+ auto svc = std::make_shared<CInterface>(CInterface{nullptr, nullptr});
+ auto svcReg = ctx.registerService<CInterface>(svc).build();
+ svcReg->wait();
+
+ std::cout << "Name is " << celix::typeName<CInterface>() << std::endl;
+ long svcId = celix_bundleContext_findService(cCtx, celix::typeName<CInterface>().c_str());
+ EXPECT_GE(svcId, 0L);
+
+ svcReg->unregister();
+ svcId = celix_bundleContext_findService(cCtx, celix::typeName<CInterface>().c_str());
+ EXPECT_GE(svcId, -1);
+
+ CInterface svc2{nullptr, nullptr};
+ auto svcReg2 = ctx.registerUnmanagedService(&svc2).build();
+
+ celix_bundleContext_waitForEvents(cCtx);
+ svcId = celix_bundleContext_findService(cCtx, celix::typeName<CInterface>().c_str());
+ EXPECT_GE(svcId, 0L);
+
+ svcReg2->unregister();
+ celix_bundleContext_waitForEvents(cCtx);
+ svcId = celix_bundleContext_findService(cCtx, celix::typeName<CInterface>().c_str());
+ EXPECT_GE(svcId, -1);
+}
+
+TEST_F(CxxBundleContextTestSuite, UseServicesTest) {
+ auto *cCtx = celix_framework_getFrameworkContext(fw.get());
+ celix::BundleContext ctx{cCtx};
+
+ auto count = ctx.useService<CInterface>().build();
+ EXPECT_EQ(count, 0);
+
+ auto svc = std::make_shared<CInterface>(CInterface{nullptr, nullptr});
+ auto svcReg1 = ctx.registerService<CInterface>(svc).build();
+ auto svcReg2 = ctx.registerService<CInterface>(svc).build();
+
+ std::atomic<int> countFromFunction{0};
+ count = ctx.useService<CInterface>().addUseCallback([&countFromFunction](CInterface&){countFromFunction += 1;}).build();
+ EXPECT_EQ(count, 1);
+ EXPECT_EQ(countFromFunction.load(), 1);
+
+ countFromFunction = 0;
+ count = ctx.useServices<CInterface>()
+ .setTimeout(std::chrono::seconds{1})
+ .addUseCallback([&countFromFunction](CInterface&, const celix::Properties& props){
+ countFromFunction += 1;
+ auto id = props.getAsLong(OSGI_FRAMEWORK_SERVICE_ID, -1L);
+ EXPECT_GT(id, -1L);
+ })
+ .build();
+ count += ctx.useServices<CInterface>().addUseCallback([&countFromFunction](CInterface&, const celix::Properties& props, const celix::Bundle& bnd) {
+ countFromFunction += 1;
+ EXPECT_GE(props.getAsLong(OSGI_FRAMEWORK_SERVICE_ID, -1L), 0);
+ EXPECT_GE(bnd.getId(), -1L);
+ }).build();
+ EXPECT_EQ(count, 4);
+ EXPECT_EQ(countFromFunction.load(), 4);
+}
+
+TEST_F(CxxBundleContextTestSuite, FindServicesTest) {
+ auto *cCtx = celix_framework_getFrameworkContext(fw.get());
+ celix::BundleContext ctx{cCtx};
+
+ auto svcId = ctx.findService<CInterface>();
+ EXPECT_EQ(svcId, -1L);
+ auto svcIds = ctx.findServices<CInterface>();
+ EXPECT_EQ(svcIds.size(), 0);
+
+
+ celix::Properties props{};
+ props["key1"] = "value1";
+ auto svc = std::make_shared<CInterface>(CInterface{nullptr, nullptr});
+ auto svcReg1 = ctx.registerService<CInterface>(svc)
+ .setProperties(props)
+ .addProperty("key2", "value2")
+ .build();
+ svcReg1->wait();
+ auto svcReg2 = ctx.registerService<CInterface>(svc).build();
+ svcReg2->wait();
+
+ svcId = ctx.findService<CInterface>();
+ EXPECT_EQ(svcId, svcReg1->getServiceId()); //svcReg1 -> registered first
+
+ svcIds = ctx.findServices<CInterface>();
+ EXPECT_EQ(svcIds.size(), 2);
+ svcIds = ctx.findServices<CInterface>("(&(key1=value1)(key2=value2))");
+ EXPECT_EQ(svcIds.size(), 1); //only 1 svc matches the filter
+
+ svcReg1->unregister();
+ svcReg1->wait();
+ svcId = ctx.findService<CInterface>();
+ EXPECT_EQ(svcId, svcReg2->getServiceId()); //svcReg2 -> svcReg1 unregistered
+}
+
+
+TEST_F(CxxBundleContextTestSuite, TrackServicesTest) {
+ auto *cCtx = celix_framework_getFrameworkContext(fw.get());
+ celix::BundleContext ctx{cCtx};
+
+ auto tracker = ctx.trackServices<CInterface>().build();
+ tracker->wait();
+ EXPECT_TRUE(tracker->isOpen());
+ EXPECT_EQ(0, tracker->getServiceCount());
+
+ celix::Properties props{};
+ props["key1"] = "value1";
+ auto svc = std::make_shared<CInterface>(CInterface{nullptr, nullptr});
+ auto svcReg1 = ctx.registerService<CInterface>(svc)
+ .setProperties(props)
+ .addProperty("key2", "value2")
+ .build();
+ svcReg1->wait();
+ auto svcReg2 = ctx.registerService<CInterface>(svc).build();
+ svcReg2->wait();
+ EXPECT_EQ(2, tracker->getServiceCount());
+
+ auto tracker2 = ctx.trackServices<CInterface>().setFilter("(key1=value1)").build();
+ tracker2->wait();
+ EXPECT_EQ(1, tracker2->getServiceCount());
+
+ std::atomic<int> count{0};
+ auto tracker3 = ctx.trackServices<CInterface>()
+ .addAddCallback([&count](const std::shared_ptr<CInterface>&) {
+ count += 1;
+ })
+ .addRemCallback([&count](const std::shared_ptr<CInterface>&) {
+ count += 1;
+ })
+ .build();
+ tracker3->wait();
+ EXPECT_EQ(2, count); //2x add called
+ svcReg1->unregister();
+ svcReg1->wait();
+ EXPECT_EQ(3, count); //2x add called, 1x rem called
+ tracker3->close();
+ tracker3->wait();
+ EXPECT_EQ(4, count); //2x add called, 2x rem called (1 rem call for closing the tracker)
+
+ EXPECT_EQ(1, tracker->getServiceCount()); //only 1 left
+
+}
+
+TEST_F(CxxBundleContextTestSuite, TrackBundlesTest) {
+ auto *cCtx = celix_framework_getFrameworkContext(fw.get());
+ celix::BundleContext ctx{cCtx};
+
+ std::atomic<int> count{0};
+ auto cb = [&count](const celix::Bundle& bnd) {
+ EXPECT_GE(bnd.getId(), 0);
+ count++;
+ };
+
+ auto tracker = ctx.trackBundles()
+ .addOnInstallCallback(cb)
+ .addOnStartCallback(cb)
+ .addOnStopCallback(cb)
+ .build();
+ tracker->wait();
+ EXPECT_EQ(celix::TrackerState::OPEN, tracker->getCurrentState());
+ EXPECT_TRUE(tracker->isOpen());
+ EXPECT_EQ(0, count.load());
+
+ long bndId = ctx.installBundle("non-existing");
+ EXPECT_EQ(-1, bndId); //not installed
+
+ long bndId1 = ctx.installBundle(TEST_BND1_LOC);
+ EXPECT_GE(bndId1, 0);
+ EXPECT_EQ(2, count.load()); // 1x install, 1x start
+
+ long bndId2 = ctx.installBundle(TEST_BND2_LOC, false);
+ EXPECT_GE(bndId1, 0);
+ EXPECT_EQ(3, count.load()); // 2x install, 1x start
+ ctx.startBundle(bndId2);
+ EXPECT_EQ(4, count.load()); // 2x install, 2x start
+
+ ctx.uninstallBundle(bndId1);
+ EXPECT_EQ(5, count.load()); // 2x install, 2x start, 1x stop
+
+ ctx.stopBundle(bndId2);
+ EXPECT_EQ(6, count.load()); // 2x install, 2x start, 2x stop
+ ctx.startBundle(bndId2);
+ EXPECT_EQ(7, count.load()); // 2x install, 3x start, 2x stop
+}
+
+TEST_F(CxxBundleContextTestSuite, OnRegisterAndUnregisterCallbacks) {
+ auto *cCtx = celix_framework_getFrameworkContext(fw.get());
+ celix::BundleContext ctx{cCtx};
+
+ std::atomic<int> count{};
+ auto callback1 = [&count](const std::shared_ptr<celix::ServiceRegistration>& reg) {
+ EXPECT_EQ(celix::ServiceRegistrationState::REGISTERED, reg->getCurrentState());
+ count++;
+ };
+ auto callback2 = [&count](const std::shared_ptr<celix::ServiceRegistration>& reg) {
+ EXPECT_EQ(celix::ServiceRegistrationState::UNREGISTERED, reg->getCurrentState());
+ count--;
+ };
+
+ auto svcReg = ctx.registerService<TestInterface>(std::make_shared<TestImplementation>())
+ .setVersion("1.0.0")
+ .addOnRegistered(callback1)
+ .addOnRegistered(callback1)
+ .addOnRegistered([](const std::shared_ptr<celix::ServiceRegistration>& reg) {
+ std::cout << "Done registering service '" << reg->getServiceName() << "' with id " << reg->getServiceId() << std::endl;
+ })
+ .addOnUnregistered(callback2)
+ .addOnUnregistered(callback2)
+ .build();
+ svcReg->wait();
+ EXPECT_EQ(count.load(), 2); //2x incr callback1
+ svcReg->unregister();
+ svcReg->wait();
+ EXPECT_EQ(count.load(), 0); //2x descr callback2
+}
+
+TEST_F(CxxBundleContextTestSuite, InstallCxxBundle) {
+ auto *cCtx = celix_framework_getFrameworkContext(fw.get());
+ celix::BundleContext ctx{cCtx};
+
+ std::string loc{SIMPLE_CXX_BUNDLE_LOC};
+ ASSERT_FALSE(loc.empty());
+ long bndId = ctx.installBundle(loc);
+ EXPECT_GE(bndId, 0);
+}
+
+TEST_F(CxxBundleContextTestSuite, LoggingUsingContext) {
+ auto *cCtx = celix_framework_getFrameworkContext(fw.get());
+ celix::BundleContext ctx{cCtx};
+ ctx.logTrace("trace");
+ ctx.logDebug("debug");
+ ctx.logInfo("info");
+ ctx.logWarn("warn");
+ ctx.logError("error");
+ ctx.logFatal("fatal");
+
+}
+
+TEST_F(CxxBundleContextTestSuite, GetFramework) {
+ auto *cCtx = celix_framework_getFrameworkContext(fw.get());
+ celix::BundleContext ctx{cCtx};
+
+ EXPECT_FALSE(ctx.getFramework()->getUUID().empty());
+ EXPECT_EQ(ctx.getFramework()->getFrameworkBundleContext()->getBundle().getId(), 0);
+}
+
+TEST_F(CxxBundleContextTestSuite, GetConfigurations) {
+ auto *cCtx = celix_framework_getFrameworkContext(fw.get());
+ celix::BundleContext ctx{cCtx};
+
+ EXPECT_EQ(ctx.getConfigProperty("non-existing", "test"), std::string{"test"});
+ EXPECT_EQ(ctx.getConfigPropertyAsLong("non-existing", -1L), -1L);
+ EXPECT_EQ(ctx.getConfigPropertyAsDouble("non-existing", 0), 0);
+ EXPECT_EQ(ctx.getConfigPropertyAsBool("non-existing", true), true);
+
+}
+
+TEST_F(CxxBundleContextTestSuite, TrackAnyServices) {
+ auto *cCtx = celix_framework_getFrameworkContext(fw.get());
+ celix::BundleContext ctx{cCtx};
+
+ auto svc1 = std::make_shared<CInterface>(CInterface{nullptr, nullptr});
+ auto svcReg1 = ctx.registerService<CInterface>(svc1).build();
+ svcReg1->wait();
+
+ auto svc2 = std::make_shared<TestImplementation>();
+ auto svcReg2 = ctx.registerService<TestInterface>(svc2).build();
+ svcReg2->wait();
+
+ auto trk = ctx.trackAnyServices().build();
+ trk->wait();
+ EXPECT_EQ(2, trk->getServiceCount());
+}
+
+TEST_F(CxxBundleContextTestSuite, TrackServiceTracker) {
+ auto *cCtx = celix_framework_getFrameworkContext(fw.get());
+ celix::BundleContext ctx{cCtx};
+
+ std::atomic<int> count{0};
+
+ auto metaTracker = ctx.trackServiceTrackers<TestInterface>()
+ .addOnTrackerCreatedCallback([&count](const celix::ServiceTrackerInfo& info) {
+ EXPECT_EQ(celix::typeName<TestInterface>(), info.serviceName);
+ count++;
+ })
+ .addOnTrackerDestroyedCallback([&count](const celix::ServiceTrackerInfo& info) {
+ EXPECT_EQ(celix::typeName<TestInterface>(), info.serviceName);
+ count--;
+ })
+ .build();
+ metaTracker->wait();
+ EXPECT_EQ(0, count.load()); // 0x created, 0x destroyed
+
+ auto trk1 = ctx.trackServices<TestInterface>().build();
+ auto trk2 = ctx.trackServices<TestInterface>().build();
+ auto trk3 = ctx.trackAnyServices().build(); //should not trigger callbacks
+ auto trk4 = ctx.trackServices<CInterface>().build(); //should not trigger callbacks
+ trk1->wait();
+ trk2->wait();
+ trk3->wait();
+ trk4->wait();
+ EXPECT_EQ(2, count.load()); // 2x created, 0x destroyed
+
+ trk1->close();
+ trk2->close();
+ trk3->close();
+ trk4->close();
+ trk1->wait();
+ trk2->wait();
+ trk3->wait();
+ trk4->wait();
+ EXPECT_EQ(0, count.load()); // 2x created, 2x destroyed
+}
+
+TEST_F(CxxBundleContextTestSuite, TrackAnyServiceTracker) {
+ auto *cCtx = celix_framework_getFrameworkContext(fw.get());
+ celix::BundleContext ctx{cCtx};
+
+ std::atomic<int> count{0};
+
+ auto metaTracker = ctx.trackAnyServiceTrackers()
+ .addOnTrackerCreatedCallback([&count](const celix::ServiceTrackerInfo& info) {
+ EXPECT_FALSE(info.filter.getFilterString().empty());
+ count++;
+ })
+ .addOnTrackerDestroyedCallback([&count](const celix::ServiceTrackerInfo& info) {
+ EXPECT_FALSE(info.filter.getFilterString().empty());
+ count--;
+ })
+ .build();
+ metaTracker->wait();
+ EXPECT_EQ(0, count.load()); // 0x created, 0x destroyed
+
+ auto trk1 = ctx.trackServices<TestInterface>().build();
+ auto trk2 = ctx.trackServices<TestInterface>().build();
+ auto trk3 = ctx.trackAnyServices().build();
+ auto trk4 = ctx.trackServices<CInterface>().build();
+ trk1->wait();
+ trk2->wait();
+ trk3->wait();
+ trk4->wait();
+ EXPECT_EQ(4, count.load()); // 4x created, 0x destroyed
+
+ trk1->close();
+ trk2->close();
+ trk3->close();
+ trk4->close();
+ trk1->wait();
+ trk2->wait();
+ trk3->wait();
+ trk4->wait();
+ EXPECT_EQ(0, count.load()); // 4x created, 4x destroyed
+}
\ No newline at end of file
diff --git a/libs/framework/gtest/src/CxxFilter_tests.cpp b/libs/framework/gtest/src/CxxFilter_tests.cpp
new file mode 100644
index 0000000..f22ac9d
--- /dev/null
+++ b/libs/framework/gtest/src/CxxFilter_tests.cpp
@@ -0,0 +1,75 @@
+/*
+ * 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/Filter.h"
+
+class CxxFilterTestSuite : public ::testing::Test {
+public:
+};
+
+
+TEST_F(CxxFilterTestSuite, CreateDestroy) {
+ //TODO support empty filter
+// celix::Filter filter{};
+// EXPECT_TRUE(filter.getCFilter() != nullptr);
+}
+
+TEST_F(CxxFilterTestSuite, FilterString) {
+ //TODO
+// celix::Filter filter1{};
+// EXPECT_EQ(std::string{}, filter1.getFilterString());
+
+ celix::Filter filter2{"(key=value)"};
+ EXPECT_EQ(std::string{"(key=value)"}, filter2.getFilterString());
+}
+
+TEST_F(CxxFilterTestSuite, EmptyFilterTest) {
+ //TODO match test that match is always true
+}
+
+TEST_F(CxxFilterTestSuite, MatchTest) {
+ celix::Filter filter1{"(key=value)"};
+ celix::Filter filter2{"(key=value2)"};
+ celix::Properties props1{};
+ props1.set("key", "value");
+ celix::Properties props2{};
+
+ EXPECT_TRUE(filter1.match(props1));
+ EXPECT_FALSE(filter2.match(props1));
+ EXPECT_FALSE(filter1.match(props2));
+ EXPECT_FALSE(filter2.match(props2));
+}
+
+TEST_F(CxxFilterTestSuite, FindAttributes) {
+ celix::Filter filter1{"(&(key1=value1)(key2=value2)(|(key3=value3)(key4=*)))"};
+
+ EXPECT_TRUE(filter1.hasAttribute("key1"));
+ EXPECT_TRUE(filter1.hasAttribute("key2"));
+ EXPECT_TRUE(filter1.hasAttribute("key3"));
+ EXPECT_TRUE(filter1.hasAttribute("key4"));
+ EXPECT_FALSE(filter1.hasAttribute("key"));
+
+ EXPECT_EQ(filter1.findAttribute("key1"), std::string{"value1"});
+ EXPECT_EQ(filter1.findAttribute("key2"), std::string{"value2"});
+ EXPECT_EQ(filter1.findAttribute("key3"), std::string{"value3"});
+ EXPECT_EQ(filter1.findAttribute("key4"), std::string{"*"});
+ EXPECT_TRUE(filter1.findAttribute("key").empty());
+}
\ No newline at end of file
diff --git a/libs/framework/gtest/src/CxxProperties_tests.cpp b/libs/framework/gtest/src/CxxProperties_tests.cpp
new file mode 100644
index 0000000..1c6651e
--- /dev/null
+++ b/libs/framework/gtest/src/CxxProperties_tests.cpp
@@ -0,0 +1,91 @@
+/*
+ * 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/Properties.h"
+
+using ::testing::MatchesRegex;
+
+class CxxPropertiesTestSuite : public ::testing::Test {
+public:
+};
+
+TEST_F(CxxPropertiesTestSuite, CreateDestroy) {
+ celix::Properties props{};
+ EXPECT_EQ(0, props.size());
+}
+
+TEST_F(CxxPropertiesTestSuite, FillAndLoop) {
+ celix::Properties props{};
+ EXPECT_EQ(0, props.size());
+
+ props["key1"] = "value1";
+ props.set("key2", "value2");
+ props.set("key3", 3.3);
+ props.set("key4", 4);
+ props.set("key5", true);
+ EXPECT_EQ(5, props.size());
+
+ 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);
+ EXPECT_EQ(props.get("key5"), "true");
+ EXPECT_EQ(props.getAsBool("key5", false), true);
+
+ int count = 0;
+ for (const auto& pair : props) {
+ EXPECT_NE(pair.first, "");
+ count++;
+ }
+ EXPECT_EQ(5, count);
+}
+
+TEST_F(CxxPropertiesTestSuite, CopyTest) {
+ celix::Properties props{};
+
+ props["key1"] = "value1";
+ props["key2"] = "value2";
+
+ celix::Properties copy = props;
+ copy["key1"] = "value1_new";
+
+ std::string v1 = props["key1"];
+ std::string v2 = copy["key1"];
+ EXPECT_EQ(v1, "value1");
+ EXPECT_EQ(v2, "value1_new");
+}
+
+TEST_F(CxxPropertiesTestSuite, WrapTest) {
+ auto *props = celix_properties_create();
+ celix_properties_set(props, "test", "test");
+
+ EXPECT_EQ(1, celix_properties_size(props));
+ {
+ auto cxxProps = celix::Properties::wrap(props);
+ EXPECT_EQ(1, cxxProps->size());
+ EXPECT_EQ(props, cxxProps->getCProperties());
+ } //NOTE cxxProps out of scope, but will not destroy celix_properties
+ EXPECT_EQ(1, celix_properties_size(props));
+
+ celix_properties_destroy(props);
+}
diff --git a/libs/framework/gtest/src/DependencyManagerTestSuite.cc b/libs/framework/gtest/src/DependencyManagerTestSuite.cc
index 419eb61..c4c00b8 100644
--- a/libs/framework/gtest/src/DependencyManagerTestSuite.cc
+++ b/libs/framework/gtest/src/DependencyManagerTestSuite.cc
@@ -20,7 +20,8 @@
#include <gtest/gtest.h>
#include <atomic>
-#include "celix_api.h"
+#include "celix/dm/DependencyManager.h"
+#include "celix_framework_factory.h"
class DependencyManagerTestSuite : public ::testing::Test {
public:
diff --git a/libs/framework/include/celix/dm/Properties.h b/libs/framework/gtest/src/HelloWorldCxxActivator.cpp
similarity index 73%
copy from libs/framework/include/celix/dm/Properties.h
copy to libs/framework/gtest/src/HelloWorldCxxActivator.cpp
index 5c33885..c7df45d 100644
--- a/libs/framework/include/celix/dm/Properties.h
+++ b/libs/framework/gtest/src/HelloWorldCxxActivator.cpp
@@ -17,11 +17,15 @@
* under the License.
*/
-#pragma once
+#include "celix/BundleActivator.h"
-#include <map>
-#include <string>
+namespace {
+ class BundleActivator {
+ public:
+ explicit BundleActivator(const std::shared_ptr<celix::BundleContext>& ctx) {
+ ctx->logInfo("Cxx Bundle Started");
+ }
+ };
+}
-namespace celix { namespace dm {
- using Properties = std::map<std::string, std::string>;
-}}
+CELIX_GEN_CXX_BUNDLE_ACTIVATOR(BundleActivator)
\ No newline at end of file
diff --git a/libs/framework/gtest/src/bundle_context_services_test.cpp b/libs/framework/gtest/src/bundle_context_services_test.cpp
index b19fbe9..87345f5 100644
--- a/libs/framework/gtest/src/bundle_context_services_test.cpp
+++ b/libs/framework/gtest/src/bundle_context_services_test.cpp
@@ -92,7 +92,7 @@ TEST_F(CelixBundleContextServicesTests, registerServiceAsync) {
celix_bundleContext_waitForAsyncRegistration(ctx, svcId);
ASSERT_GE(celix_bundleContext_findService(ctx, calcName), 0L);
- celix_bundleContext_unregisterServiceAsync(ctx, svcId, NULL, NULL);
+ celix_bundleContext_unregisterServiceAsync(ctx, svcId, nullptr, nullptr);
celix_bundleContext_waitForAsyncUnregistration(ctx, svcId);
ASSERT_LT(celix_bundleContext_findService(ctx, calcName), 0L);
};
@@ -105,10 +105,10 @@ TEST_F(CelixBundleContextServicesTests, incorrectUnregisterCalls) {
};
TEST_F(CelixBundleContextServicesTests, incorrectAsyncUnregisterCalls) {
- celix_bundleContext_unregisterServiceAsync(ctx, 1, NULL, NULL);
- celix_bundleContext_unregisterServiceAsync(ctx, 2, NULL, NULL);
- celix_bundleContext_unregisterServiceAsync(ctx, -1, NULL, NULL);
- celix_bundleContext_unregisterServiceAsync(ctx, -2, NULL, NULL);
+ celix_bundleContext_unregisterServiceAsync(ctx, 1, nullptr, nullptr);
+ celix_bundleContext_unregisterServiceAsync(ctx, 2, nullptr, nullptr);
+ celix_bundleContext_unregisterServiceAsync(ctx, -1, nullptr, nullptr);
+ celix_bundleContext_unregisterServiceAsync(ctx, -2, nullptr, nullptr);
};
TEST_F(CelixBundleContextServicesTests, registerMultipleAndUseServices) {
@@ -286,7 +286,7 @@ TEST_F(CelixBundleContextServicesTests, registerAsyncAndUseServiceWithTimeout) {
EXPECT_TRUE(result.get()); //should return true after waiting for the registered service.
- celix_bundleContext_unregisterServiceAsync(ctx, svcId, NULL, NULL);
+ celix_bundleContext_unregisterServiceAsync(ctx, svcId, nullptr, nullptr);
celix_bundleContext_waitForAsyncUnregistration(ctx, svcId);
@@ -516,7 +516,7 @@ TEST_F(CelixBundleContextServicesTests, servicesTrackerTestAsync) {
ASSERT_TRUE(svcId2 >= 0);
ASSERT_EQ(2, count);
- celix_bundleContext_unregisterServiceAsync(ctx, svcId1, NULL, NULL);
+ celix_bundleContext_unregisterServiceAsync(ctx, svcId1, nullptr, nullptr);
celix_bundleContext_waitForAsyncUnregistration(ctx, svcId1);
ASSERT_EQ(1, count);
@@ -593,13 +593,13 @@ TEST_F(CelixBundleContextServicesTests, servicesTrackerTestWithProperties) {
int count = 0;
auto add = [](void *handle, void *svc, const properties_t *props) {
ASSERT_TRUE(svc != nullptr);
- ASSERT_STRCASEEQ("C", celix_properties_get(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, nullptr));
+ ASSERT_TRUE(props != nullptr);
int *c = static_cast<int*>(handle);
*c += 1;
};
auto remove = [](void *handle, void *svc, const properties_t *props) {
ASSERT_TRUE(svc != nullptr);
- ASSERT_STRCASEEQ("C", celix_properties_get(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, nullptr));
+ ASSERT_TRUE(props != nullptr);
int *c = static_cast<int*>(handle);
*c -= 1;
};
@@ -630,14 +630,14 @@ TEST_F(CelixBundleContextServicesTests, servicesTrackerTestWithOwner) {
int count = 0;
auto add = [](void *handle, void *svc, const properties_t *props, const bundle_t *svcOwner) {
ASSERT_TRUE(svc != nullptr);
- ASSERT_STRCASEEQ("C", celix_properties_get(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, nullptr));
+ ASSERT_TRUE(props != nullptr);
ASSERT_TRUE(celix_bundle_getId(svcOwner) >= 0);
int *c = static_cast<int*>(handle);
*c += 1;
};
auto remove = [](void *handle, void *svc, const properties_t *props, const bundle_t *svcOwner) {
ASSERT_TRUE(svc != nullptr);
- ASSERT_STRCASEEQ("C", celix_properties_get(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, nullptr));
+ ASSERT_TRUE(props != nullptr);
ASSERT_TRUE(celix_bundle_getId(svcOwner) >= 0);
int *c = static_cast<int*>(handle);
*c -= 1;
@@ -818,7 +818,7 @@ TEST_F(CelixBundleContextServicesTests, servicesTrackerSetTest) {
//unregister svc3 should lead to set (new highest ranking)
celix_bundleContext_unregisterService(ctx, svcId3); //call 3
- celix_bundleContext_stopTracker(ctx, trackerId); //call 4 (NULL)
+ celix_bundleContext_stopTracker(ctx, trackerId); //call 4 (nullptr)
celix_bundleContext_unregisterService(ctx, svcId1);
celix_bundleContext_unregisterService(ctx, svcId2);
celix_bundleContext_unregisterService(ctx, svcId4);
@@ -962,7 +962,7 @@ TEST_F(CelixBundleContextServicesTests, asyncServiceFactoryTest) {
ASSERT_EQ(2, count); //expecting getService & unGetService to be called during the useService call.
- celix_bundleContext_unregisterServiceAsync(ctx, facId, NULL, NULL);
+ celix_bundleContext_unregisterServiceAsync(ctx, facId, nullptr, nullptr);
}
TEST_F(CelixBundleContextServicesTests, findServicesTest) {
@@ -1004,13 +1004,11 @@ TEST_F(CelixBundleContextServicesTests, trackServiceTrackerTest) {
auto add = [](void *handle, const celix_service_tracker_info_t *info) {
EXPECT_STRCASEEQ("example", info->serviceName);
- EXPECT_STRCASEEQ(CELIX_FRAMEWORK_SERVICE_C_LANGUAGE, info->serviceLanguage);
auto *c = static_cast<int*>(handle);
*c += 1;
};
auto remove = [](void *handle, const celix_service_tracker_info_t *info) {
EXPECT_STRCASEEQ("example", info->serviceName);
- EXPECT_STRCASEEQ(CELIX_FRAMEWORK_SERVICE_C_LANGUAGE, info->serviceLanguage);
auto *c = static_cast<int*>(handle);
*c -= 1;
};
diff --git a/libs/framework/include/celix/Builders.h b/libs/framework/include/celix/Builders.h
new file mode 100644
index 0000000..795ce05
--- /dev/null
+++ b/libs/framework/include/celix/Builders.h
@@ -0,0 +1,600 @@
+/*
+ * 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 <memory>
+#include <functional>
+
+#include "celix/ServiceRegistration.h"
+#include "celix/Trackers.h"
+
+namespace celix {
+
+ /**
+ * Fluent builder API to build a new service registration for a service of type I.
+ *
+ * \warning Not thread safe.
+ * @tparam I The service type (Note should be the abstract interface, not the interface implementer)
+ */
+ template<typename I>
+ class ServiceRegistrationBuilder {
+ private:
+ friend class BundleContext;
+
+ //NOTE private to prevent move so that a build() call cannot be forgotten
+ ServiceRegistrationBuilder(ServiceRegistrationBuilder&&) = default;
+ public:
+ ServiceRegistrationBuilder(std::shared_ptr<celix_bundle_context_t> _cCtx, std::shared_ptr<I> _svc, std::string _name) :
+ cCtx{std::move(_cCtx)},
+ svc{std::move(_svc)},
+ name{std::move(_name)} {
+
+ }
+
+ ServiceRegistrationBuilder& operator=(ServiceRegistrationBuilder&&) = delete;
+ ServiceRegistrationBuilder(const ServiceRegistrationBuilder&) = delete;
+ ServiceRegistrationBuilder operator=(const ServiceRegistrationBuilder&) = delete;
+
+ /**
+ * Set the service version.
+ * This will lead to a 'service.version' service property.
+ */
+ ServiceRegistrationBuilder& setVersion(std::string v) { version = std::move(v); return *this; }
+
+ /**
+ * Add a property to the service properties.
+ * 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; }
+
+ /**
+ * 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; }
+
+ /**
+ * Add a property to the service properties.
+ * 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; }
+
+ /**
+ * Set the service properties.
+ * Note this call will clear any already set properties.
+ */
+ ServiceRegistrationBuilder& setProperties(celix::Properties p) { properties = std::move(p); return *this; }
+
+ /**
+ * Add the properties to the service properties.
+ * Note this call will add these properties to the already set properties.
+ * If a key is already present the value will be overridden.
+ */
+ ServiceRegistrationBuilder& addProperties(const celix::Properties& props) {
+ for (const auto& pair : props) {
+ properties.set(pair.first, pair.second);
+ }
+ return *this;
+ }
+
+ /**
+ * Adds an on registered callback for the service registration.
+ * This callback will be called on the Celix event thread when the service is registered (REGISTERED state)
+ */
+ ServiceRegistrationBuilder& addOnRegistered(std::function<void(const std::shared_ptr<ServiceRegistration>&)> callback) {
+ onRegisteredCallbacks.emplace_back(std::move(callback));
+ return *this;
+ }
+
+ /**
+ * Adds an on unregistered callback for the service registration.
+ * This callback will be called on the Celix event thread when the service is unregistered (UNREGISTERED state)
+ */
+ ServiceRegistrationBuilder& addOnUnregistered(std::function<void(const std::shared_ptr<ServiceRegistration>&)> callback) {
+ onUnregisteredCallbacks.emplace_back(std::move(callback));
+ return *this;
+ }
+
+ /**
+ * "Builds" the service registration and return a ServiceRegistration.
+ *
+ * The ServiceRegistration will async register the service to the Celix framwork and unregister the service if
+ * the ServiceRegistration is destroyed.
+ *
+ */
+ std::shared_ptr<ServiceRegistration> build() {
+ auto result = std::make_shared<ServiceRegistration>(cCtx, std::move(svc), std::move(name), std::move(version), std::move(properties), std::move(onRegisteredCallbacks), std::move(onUnregisteredCallbacks));
+ result->setSelf(result);
+ //TODO after moves , builder is not valid anymore. TBD howto handle this
+ return result;
+ }
+ private:
+ const std::shared_ptr<celix_bundle_context_t> cCtx;
+ std::shared_ptr<I> svc;
+ std::string name;
+ std::string version{};
+ celix::Properties properties{};
+ std::vector<std::function<void(const std::shared_ptr<ServiceRegistration>&)>> onRegisteredCallbacks{};
+ std::vector<std::function<void(const std::shared_ptr<ServiceRegistration>&)>> onUnregisteredCallbacks{};
+ };
+
+ /**
+ * Fluent builder API to use a service(s) of type I.
+ *
+ * \warning Not thread safe.
+ * @tparam I The service type to use
+ */
+ template<typename I>
+ class UseServiceBuilder {
+ private:
+ friend class BundleContext;
+
+ //NOTE private to prevent move so that a build() call cannot be forgotten
+ UseServiceBuilder(UseServiceBuilder&&) = default;
+ public:
+ explicit UseServiceBuilder(std::shared_ptr<celix_bundle_context_t> _cCtx, std::string _name, bool _useSingleService = true) :
+ cCtx{std::move(_cCtx)},
+ name{std::move(_name)},
+ useSingleService{_useSingleService} {
+ }
+
+ UseServiceBuilder& operator=(UseServiceBuilder&&) = delete;
+ UseServiceBuilder(const UseServiceBuilder&) = delete;
+ UseServiceBuilder operator=(const UseServiceBuilder&) = delete;
+
+ /**
+ * Set filter to be used to select a service.
+ * The filter must be LDAP filter.
+ * Example: "(property_key=value)"
+ */
+ UseServiceBuilder& setFilter(std::string f) { filter = std::move(f); return *this; }
+
+ /**
+ * Sets a optional timeout.
+ * If the timeout is > 0 and there is no matching service, the "build" will block
+ * until a matching service is found or the timeout is expired.
+ *
+ * Note: timeout is only valid if the a single service is used.
+ *
+ */
+ template <typename Rep, typename Period>
+ UseServiceBuilder& setTimeout(std::chrono::duration<Rep, Period> duration) {
+ auto micro = std::chrono::duration_cast<std::chrono::microseconds>(duration).count();
+ timeoutInSeconds = micro / 1000000;
+ return *this;
+ }
+
+ /**
+ * Adds a use callback function which will be called when the UseServiceBuilder is
+ * "build".
+ *
+ * The use callback function has 1 argument: a reference to the matching service.
+ */
+ UseServiceBuilder& addUseCallback(std::function<void(I&)> cb) {
+ callbacks.emplace_back(std::move(cb));
+ return *this;
+ }
+
+ /**
+ * Adds a use callback function which will be called when the UseServiceBuilder is
+ * "build".
+ *
+ * The use callback function has 2 arguments:
+ * - A reference to the matching service.
+ * - A const reference to the matching service properties.
+ */
+ UseServiceBuilder& addUseCallback(std::function<void(I&, const celix::Properties&)> cb) {
+ callbacksWithProperties.emplace_back(std::move(cb));
+ return *this;
+ }
+
+ /**
+ * Adds a use callback function which will be called when the UseServiceBuilder is
+ * "build".
+ *
+ * The use callback function has 3 arguments:
+ * - A reference to the matching service.
+ * - A const reference to the matching service properties.
+ * - A const reference to the bundle owning the matching service.
+ */
+ UseServiceBuilder& addUseCallback(std::function<void(I&, const celix::Properties&, const celix::Bundle&)> cb) {
+ callbacksWithOwner.emplace_back(std::move(cb));
+ return *this;
+ }
+
+ /**
+ * "Builds" the UseServiceBuild and returns directly if no matching service is found
+ * or blocks until:
+ * - All the use callback functions are called with the highest ranking matching service
+ * - The timeout has expired
+ *
+ * \returns the number of service called (1 or 0).
+ */
+ std::size_t build() {
+ celix_service_use_options_t opts{};
+ opts.filter.serviceName = name.empty() ? nullptr : name.c_str();
+ opts.filter.ignoreServiceLanguage = true;
+ opts.filter.filter = filter.empty() ? nullptr : filter.c_str();
+ opts.filter.versionRange = versionRange.empty() ? nullptr : versionRange.c_str();
+ opts.waitTimeoutInSeconds = timeoutInSeconds;
+ opts.callbackHandle = this;
+ 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)};
+ auto props = celix::Properties::wrap(cProps);
+ for (const auto& func : builder->callbacks) {
+ func(*svc);
+ }
+ for (const auto& func : builder->callbacksWithProperties) {
+ func(*svc, *props);
+ }
+ for (const auto& func : builder->callbacksWithOwner) {
+ func(*svc, *props, bnd);
+ }
+ };
+
+ if (useSingleService) {
+ bool called = celix_bundleContext_useServiceWithOptions(cCtx.get(), &opts);
+ return called ? 1 : 0;
+ } else {
+ return celix_bundleContext_useServicesWithOptions(cCtx.get(), &opts);
+ }
+ }
+ private:
+ const std::shared_ptr<celix_bundle_context_t> cCtx;
+ const std::string name;
+ const bool useSingleService;
+ double timeoutInSeconds{0};
+ std::string filter{};
+ std::string versionRange{};
+ std::vector<std::function<void(I&)>> callbacks{};
+ std::vector<std::function<void(I&, const celix::Properties&)>> callbacksWithProperties{};
+ std::vector<std::function<void(I&, const celix::Properties&, const celix::Bundle&)>> callbacksWithOwner{};
+ };
+
+ /**
+ * Fluent builder API to track services of type I.
+ *
+ * \warning Not thread safe.
+ * @tparam I
+ */
+ template<typename I>
+ class ServiceTrackerBuilder {
+ private:
+ friend class BundleContext;
+
+ //NOTE private to prevent move so that a build() call cannot be forgotten
+ ServiceTrackerBuilder(ServiceTrackerBuilder&&) = default;
+ public:
+ explicit ServiceTrackerBuilder(std::shared_ptr<celix_bundle_context_t> _cCtx, std::string _name) :
+ cCtx{std::move(_cCtx)},
+ name{std::move(_name)} {}
+
+ ServiceTrackerBuilder& operator=(ServiceTrackerBuilder&&) = delete;
+ ServiceTrackerBuilder(const ServiceTrackerBuilder&) = delete;
+ ServiceTrackerBuilder operator=(const ServiceTrackerBuilder&) = delete;
+
+ /**
+ * Set filter to be used to matching services.
+ * The filter must be LDAP filter.
+ * Example: "(property_key=value)"
+ */
+ ServiceTrackerBuilder& setFilter(std::string f) { filter = std::move(f); return *this; }
+
+ /**
+ * Adds a add callback function, which will be called - on the Celix event thread -
+ * when a new service match is found.
+ *
+ * The add callback function has 1 argument: A shared ptr to the added service.
+ */
+ ServiceTrackerBuilder& addAddCallback(std::function<void(std::shared_ptr<I>)> add) {
+ addCallbacks.emplace_back([add](std::shared_ptr<I> svc, std::shared_ptr<const celix::Properties>, const celix::Bundle&) {
+ add(svc);
+ });
+ return *this;
+ }
+
+ /**
+ * Adds a add callback function, which will be called - on the Celix event thread -
+ * when a new service match is found.
+ *
+ * The add callback function has 2 arguments:
+ * - A shared ptr to the added service.
+ * - A shared ptr to the added service properties.
+ */
+ ServiceTrackerBuilder& addAddWithPropertiesCallback(std::function<void(std::shared_ptr<I>, std::shared_ptr<const celix::Properties>)> add) {
+ addCallbacks.emplace_back([add](std::shared_ptr<I> svc, std::shared_ptr<const celix::Properties> props, const celix::Bundle&) {
+ add(svc, props);
+ });
+ return *this;
+ }
+
+ /**
+ * Adds a add callback function, which will be called - on the Celix event thread -
+ * when a new service match is found.
+ *
+ * The add callback function has 3 arguments:
+ * - A shared ptr to the added service.
+ * - A shared ptr to the added service properties.
+ * - A shared ptr to the bundle owning the added service.
+ */
+ ServiceTrackerBuilder& addAddWithOwnerCallback(std::function<void(std::shared_ptr<I>, std::shared_ptr<const celix::Properties>, const celix::Bundle&)> add) {
+ addCallbacks.emplace_back([add](std::shared_ptr<I> svc, std::shared_ptr<const celix::Properties> props, const celix::Bundle& bnd) {
+ add(svc, props, bnd);
+ });
+ return *this;
+ }
+
+ /**
+ * Adds a remove callback function, which will be called - on the Celix event thread -
+ * when a service match is being removed.
+ *
+ * The remove callback function has 1 arguments: A shared ptr to the removing service.
+ */
+ ServiceTrackerBuilder& addRemCallback(std::function<void(std::shared_ptr<I>)> remove) {
+ remCallbacks.emplace_back([remove](std::shared_ptr<I> svc, std::shared_ptr<const celix::Properties>, const celix::Bundle&) {
+ remove(svc);
+ });
+ return *this;
+ }
+
+ /**
+ * Adds a remove callback function, which will be called - on the Celix event thread -
+ * when a service match is being removed.
+ *
+ * The remove callback function has 2 arguments:
+ * - A shared ptr to the removing service.
+ * - A shared ptr to the removing service properties.
+ */
+ ServiceTrackerBuilder& addRemWithPropertiesCallback(std::function<void(std::shared_ptr<I>, std::shared_ptr<const celix::Properties>)> remove) {
+ remCallbacks.emplace_back([remove](std::shared_ptr<I> svc, std::shared_ptr<const celix::Properties> props, const celix::Bundle&) {
+ remove(svc, props);
+ });
+ return *this;
+ }
+
+ /**
+ * Adds a remove callback function, which will be called - on the Celix event thread -
+ * when a service match is being removed.
+ *
+ * The remove callback function has 3 arguments:
+ * - A shared ptr to the removing service.
+ * - A shared ptr to the removing service properties.
+ * - A shared ptr to the bundle owning the removing service.
+ */
+ ServiceTrackerBuilder& addRemWithOwnerCallback(std::function<void(std::shared_ptr<I>, std::shared_ptr<const celix::Properties>, const celix::Bundle&)> remove) {
+ remCallbacks.emplace_back([remove](std::shared_ptr<I> svc, std::shared_ptr<const celix::Properties> props, const celix::Bundle& bnd) {
+ remove(svc, props, bnd);
+ });
+ return *this;
+ }
+
+ /**
+ * Adds a set callback function, which will be called - on the Celix event thread -
+ * when there is a new highest ranking service match.
+ * This can can also be an empty match (nullptr).
+ *
+ * The set callback function has 2 arguments: A shared ptr to the highest
+ * ranking service match or nullptr.
+ */
+ ServiceTrackerBuilder& addSetCallback(std::function<void(std::shared_ptr<I>)> set) {
+ setCallbacks.emplace_back([set](std::shared_ptr<I> svc, std::shared_ptr<const celix::Properties>, std::shared_ptr<const celix::Bundle>) {
+ set(std::move(svc));
+ });
+ return *this;
+ }
+
+ /**
+ * Adds a set callback function, which will be called - on the Celix event thread -
+ * when there is a new highest ranking service match.
+ * This can can also be an empty match (nullptr).
+ *
+ * The set callback function has 2 arguments:
+ * - A shared ptr to the highest ranking service match or nullptr.
+ * - A const shared ptr to the set service properties or nullptr (if the service is nullptr).
+ */
+ ServiceTrackerBuilder& addSetWithPropertiesCallback(std::function<void(std::shared_ptr<I>, std::shared_ptr<const celix::Properties>)> set) {
+ setCallbacks.emplace_back([set](std::shared_ptr<I> svc, std::shared_ptr<const celix::Properties> props, std::shared_ptr<const celix::Bundle>) {
+ set(std::move(svc), std::move(props));
+ });
+ return *this;
+ }
+
+ /**
+ * Adds a set callback function, which will be called - on the Celix event thread -
+ * when there is a new highest ranking service match.
+ * This can can also be an empty match (nullptr).
+ *
+ * The set callback function has 3 arguments:
+ * - A shared ptr to the highest ranking service match or nullptr.
+ * - A const shared ptr to the set service properties or nullptr (if the service is nullptr).
+ * - A const shared ptr to the bundle owning the set service or nullptr (if the service is nullptr).
+ */
+ ServiceTrackerBuilder& addSetWithOwner(std::function<void(std::shared_ptr<I>, std::shared_ptr<const celix::Properties>, std::shared_ptr<const celix::Bundle>)> set) {
+ setCallbacks.emplace_back(std::move(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;
+ }
+
+ //TODO add function to register done call backs -> addOnStarted / addOnStopped (inheritance?)
+
+ /**
+ * "Builds" the service tracker and returns a ServiceTracker.
+ *
+ * The ServiceTracker will be started async.
+ */
+ std::shared_ptr<ServiceTracker<I>> build() {
+ auto tracker = std::make_shared<ServiceTracker<I>>(cCtx, std::move(name), std::move(versionRange), std::move(filter), std::move(setCallbacks), std::move(addCallbacks), std::move(remCallbacks));
+ tracker->open();
+ //TODO after moves , builder is not valid anymore. TBD howto handle this
+ return tracker;
+ }
+ private:
+ const std::shared_ptr<celix_bundle_context_t> cCtx;
+ std::string name;
+ std::string filter{};
+ std::string versionRange{};
+ std::vector<std::function<void(std::shared_ptr<I>, std::shared_ptr<const celix::Properties>, std::shared_ptr<const celix::Bundle>)>> setCallbacks{};
+ std::vector<std::function<void(std::shared_ptr<I>, std::shared_ptr<const celix::Properties>, const celix::Bundle&)>> addCallbacks{}; //TODO make bundle arg std::shared_ptr
+ std::vector<std::function<void(std::shared_ptr<I>, std::shared_ptr<const celix::Properties>, const celix::Bundle&)>> remCallbacks{}; //TODO make bundle arg std::shared_ptr
+ };
+
+ /**
+ * Fluent builder API to track bundles.
+ * \warning Not thread safe.
+ */
+ class BundleTrackerBuilder {
+ private:
+ friend class BundleContext;
+
+ //NOTE private to prevent move so that a build() call cannot be forgotten
+ BundleTrackerBuilder(BundleTrackerBuilder &&) = default;
+ public:
+ explicit BundleTrackerBuilder(std::shared_ptr<celix_bundle_context_t> _cCtx) : cCtx{std::move(_cCtx)} {}
+
+ BundleTrackerBuilder &operator=(BundleTrackerBuilder &&) = delete;
+ BundleTrackerBuilder(const BundleTrackerBuilder &) = delete;
+ BundleTrackerBuilder operator=(const BundleTrackerBuilder &) = delete;
+
+ BundleTrackerBuilder& includeFrameworkBundleInCallback() {
+ includeFrameworkBundle = true;
+ return *this;
+ }
+
+ /**
+ * Adds a "on install" callback function, which will be called - on the Celix event thread -
+ * when a new bundle has been installed.
+ *
+ * The "on install" callback function has 1 arguments: A const reference to the installed bundle.
+ */
+ BundleTrackerBuilder& addOnInstallCallback(std::function<void(const celix::Bundle&)> callback) {
+ onInstallCallbacks.push_back(std::move(callback));
+ return *this;
+ }
+
+ /**
+ * Adds a "on start" callback function, which will be called - on the Celix event thread -
+ * when a new bundle has been started.
+ *
+ * The "on start" callback function has 1 arguments: A const reference to the started bundle.
+ */
+ BundleTrackerBuilder& addOnStartCallback(std::function<void(const celix::Bundle&)> callback) {
+ onStartCallbacks.push_back(std::move(callback));
+ return *this;
+ }
+
+ /**
+ * Adds a "on stop" callback function, which will be called - on the Celix event thread -
+ * when a new bundle has been stopped.
+ *
+ * The "on stop" callback function has 1 arguments: A const reference to the stopped bundle.
+ */
+ BundleTrackerBuilder& addOnStopCallback(std::function<void(const celix::Bundle&)> callback) {
+ onStopCallbacks.push_back(std::move(callback));
+ return *this;
+ }
+
+ /**
+ * "Builds" the bundle tracker and returns a BundleTracker.
+ *
+ * The BundleTracker will be started async.
+ */
+ std::shared_ptr<BundleTracker> build() {
+ auto tracker = std::make_shared<BundleTracker>(cCtx, includeFrameworkBundle, std::move(onInstallCallbacks), std::move(onStartCallbacks), std::move(onStopCallbacks));
+ tracker->open();
+ return tracker;
+ }
+ private:
+ const std::shared_ptr<celix_bundle_context_t> cCtx;
+ bool includeFrameworkBundle{false};
+ std::vector<std::function<void(const celix::Bundle&)>> onInstallCallbacks{};
+ std::vector<std::function<void(const celix::Bundle&)>> onStartCallbacks{};
+ std::vector<std::function<void(const celix::Bundle&)>> onStopCallbacks{};
+ };
+
+ /**
+ * Fluent builder API to track service trackers.
+ *
+ * \warning Not thread safe.
+ */
+ class MetaTrackerBuilder {
+ private:
+ friend class BundleContext;
+
+ //NOTE private to prevent move so that a build() call cannot be forgotten
+ MetaTrackerBuilder(MetaTrackerBuilder &&) = default;
+ public:
+ explicit MetaTrackerBuilder(std::shared_ptr<celix_bundle_context_t> _cCtx, std::string _serviceName) :
+ cCtx{std::move(_cCtx)},
+ serviceName{std::move(_serviceName)}
+ {}
+
+ MetaTrackerBuilder &operator=(MetaTrackerBuilder &&) = delete;
+ MetaTrackerBuilder(const MetaTrackerBuilder &) = delete;
+ MetaTrackerBuilder operator=(const MetaTrackerBuilder &) = delete;
+
+ /**
+ * Adds a "on tracker created" callback function, which will be called - on the Celix event thread -
+ * when a new service tracker has been created.
+ *
+ * The "on tracker created" callback function has 1 arguments: A const reference to a ServiceTrackerInfo object.
+ */
+ MetaTrackerBuilder& addOnTrackerCreatedCallback(std::function<void(const ServiceTrackerInfo&)> cb) {
+ onTrackerCreated.emplace_back(std::move(cb));
+ return *this;
+ }
+
+ /**
+ * Adds a "on tracker destroyed" callback function, which will be called - on the Celix event thread -
+ * when a new service tracker has been destroyed.
+ *
+ * The "on tracker destroyed" callback function has 1 arguments: A const reference to a ServiceTrackerInfo object.
+ */
+ MetaTrackerBuilder& addOnTrackerDestroyedCallback(std::function<void(const ServiceTrackerInfo&)> cb) {
+ onTrackerDestroyed.emplace_back(std::move(cb));
+ return *this;
+ }
+
+ /**
+ * "Builds" the meta tracker and returns a MetaTracker.
+ *
+ * The MetaTracker will be started async.
+ */
+ std::shared_ptr<MetaTracker> build() {
+ auto tracker = std::make_shared<MetaTracker>(cCtx, std::move(serviceName), std::move(onTrackerCreated), std::move(onTrackerDestroyed));
+ tracker->open();
+ return tracker;
+ }
+ private:
+ const std::shared_ptr<celix_bundle_context_t> cCtx;
+ std::string serviceName;
+ std::vector<std::function<void(const ServiceTrackerInfo&)>> onTrackerCreated{};
+ std::vector<std::function<void(const ServiceTrackerInfo&)>> onTrackerDestroyed{};
+ };
+}
\ No newline at end of file
diff --git a/examples/celix-examples/hello_world_cxx/src/BundleActivator.cc b/libs/framework/include/celix/Bundle.h
similarity index 57%
copy from examples/celix-examples/hello_world_cxx/src/BundleActivator.cc
copy to libs/framework/include/celix/Bundle.h
index 2921ba7..b8aa71d 100644
--- a/examples/celix-examples/hello_world_cxx/src/BundleActivator.cc
+++ b/libs/framework/include/celix/Bundle.h
@@ -17,29 +17,33 @@
* under the License.
*/
+#pragma once
+
#include <memory>
-#include <iostream>
-#include <celix_api.h>
+#include "celix_bundle.h"
-namespace /*anon*/ {
+namespace celix {
- class BundleActivator {
+ /**
+ * TODO
+ * \note Thread safe.
+ */
+ class Bundle {
public:
- BundleActivator(std::shared_ptr<celix::dm::DependencyManager> _mng) : mng{std::move(_mng)} {
- std::cout << "Hello world from C++ bundle with id " << bndId() << std::endl;
- }
- ~BundleActivator() {
- std::cout << "Goodbye world from C++ bundle with id " << bndId() << std::endl;
+ explicit Bundle(celix_bundle_t *_cBnd) : cBnd{_cBnd, [](celix_bundle_t*){/*nop*/}}{}
+
+ long getId() const { return celix_bundle_getId(cBnd.get()); }
+
+ std::string getEntry(const std::string& path) const {
+ std::string result{};
+ const char* entry = celix_bundle_getEntry(cBnd.get(), path.c_str());
+ if (entry != nullptr) {
+ result = std::string{entry};
+ }
+ return result;
}
private:
- long bndId() const {
- return celix_bundle_getId(celix_bundleContext_getBundle(mng->bundleContext()));
- }
-
- std::shared_ptr<celix::dm::DependencyManager> mng;
+ const std::shared_ptr<celix_bundle_t> cBnd;
};
-
-}
-
-CELIX_GEN_CXX_BUNDLE_ACTIVATOR(BundleActivator)
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/libs/framework/include/celix/BundleActivator.h b/libs/framework/include/celix/BundleActivator.h
new file mode 100644
index 0000000..617a692
--- /dev/null
+++ b/libs/framework/include/celix/BundleActivator.h
@@ -0,0 +1,105 @@
+/*
+ * 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 <memory>
+#include <celix/dm/DependencyManager.h>
+
+#include "celix_bundle_activator.h"
+#include "celix/BundleContext.h"
+
+namespace celix {
+ namespace impl {
+
+ template<typename I>
+ struct BundleActivatorData {
+ std::weak_ptr<celix::BundleContext> ctx;
+ std::weak_ptr<celix::dm::DependencyManager> dm;
+ 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 dm = std::make_shared<celix::dm::DependencyManager>(cCtx);
+ auto act = std::unique_ptr<I>(new I{ctx});
+ auto *data = new BundleActivatorData<I>{std::move(ctx), std::move(dm), 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 = std::make_shared<celix::dm::DependencyManager>(cCtx);
+ auto act = std::unique_ptr<I>(new I{dm});
+ dm->start();
+ auto *data = new BundleActivatorData<I>{std::move(ctx), std::move(dm), std::move(act)};
+ *out = (void *) data;
+ return CELIX_SUCCESS;
+ }
+
+ template<typename I>
+ celix_status_t destroyActivator(void *userData) {
+ auto *data = static_cast<BundleActivatorData<I> *>(userData);
+ data->bundleActivator = nullptr;
+ while (!data->ctx.expired()) {
+ std::cerr << "Cannot destroy bundle. Bundle context is still in use. Count is " << data->ctx.use_count()
+ << std::endl;
+ }
+ delete data;
+ return CELIX_SUCCESS;
+ }
+ }
+}
+
+/**
+ * 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:
+ * - bundleActivator_create which allocates a pointer to the provided type.
+ * - bundleActivator_start/stop which will call the respectively provided typed start/stop functions.
+ * - bundleActivator_destroy will free the allocated for the provided type.
+ *
+ * @param type The activator type (e.g. 'ShellActivator'). A type which should have a constructor with a single arugment of std::shared_ptr<DependencyManager>.
+ */
+#define CELIX_GEN_CXX_BUNDLE_ACTIVATOR(actType) \
+extern "C" celix_status_t bundleActivator_create(celix_bundle_context_t *context, void** userData) { \
+ return celix::impl::createActivator<actType>(context, userData); \
+} \
+ \
+extern "C" celix_status_t bundleActivator_start(void *, celix_bundle_context_t *) { \
+ /*nop*/ \
+ return CELIX_SUCCESS; \
+} \
+ \
+extern "C" celix_status_t bundleActivator_stop(void *, celix_bundle_context_t*) { \
+ /*nop*/ \
+ return CELIX_SUCCESS; \
+} \
+ \
+extern "C" celix_status_t bundleActivator_destroy(void *userData, celix_bundle_context_t*) { \
+ return celix::impl::destroyActivator<actType>(userData); \
+} \
+
diff --git a/libs/framework/include/celix/BundleContext.h b/libs/framework/include/celix/BundleContext.h
new file mode 100644
index 0000000..2136381
--- /dev/null
+++ b/libs/framework/include/celix/BundleContext.h
@@ -0,0 +1,505 @@
+/*
+ * 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 <memory>
+#include <mutex>
+#include <thread>
+#include <cstdarg>
+
+#include "celix_bundle_context.h"
+
+#include "celix/Builders.h"
+#include "celix/Properties.h"
+#include "celix/ServiceRegistration.h"
+#include "celix/Trackers.h"
+#include "celix/Bundle.h"
+#include "celix/Framework.h"
+
+#include "celix/dm/DependencyManager.h" //TODO, TBD include or forward declaration?
+
+namespace celix {
+
+ /**
+ * TODO
+ * \note Thread safe.
+ */
+ class BundleContext {
+ public:
+ explicit BundleContext(celix_bundle_context_t* _cCtx) :
+ cCtx{_cCtx, [](celix_bundle_context_t*){/*nop*/}},
+ dm{std::make_shared<celix::dm::DependencyManager>(_cCtx)},
+ bnd{celix_bundleContext_getBundle(_cCtx)} {}
+
+ /**
+ * Register a service in the Celix framework using a fluent builder API.
+ * The service registration can be fine tuned using the returned ServiceRegistrationBuilder API.
+ *
+ * Example:
+ * shared_ptr<celix::BundleContext> ctx = ...
+ * auto svcReg = ctx->registerService<IExample>(std::make_shared<ExampleImpl>())
+ * .setVersion("1.0.0")
+ * .addProperty("key1", "value1")
+ * .addOnRegistered([](const std::shared_ptr<celix::ServiceRegistration>& reg) {
+ * std::cout << "Done registering service '" << reg->getServiceName() << "' with id " << reg->getServiceId() << std::endl;
+ * })
+ * .build();
+ *
+ * @tparam I The service type (Note should be the abstract interface, not the interface implementer)
+ * @tparam Implementer The service implementer.
+ * @param implementer The service implementer.
+ * @param name The optional name of the service. If not provided celix::typeName<I> will be used to defer the service name.
+ * @return A ServiceRegistrationBuilder object.
+ */
+ template<typename I, typename Implementer>
+ ServiceRegistrationBuilder<I> registerService(std::shared_ptr<Implementer> implementer, const std::string& name = {}) {
+ std::shared_ptr<I> svc = implementer; //note Implement should be derived from I
+ return ServiceRegistrationBuilder<I>{cCtx, std::move(svc), celix::typeName<I>(name)};
+ }
+
+ /**
+ * Same as registerService, but then with an unmanaged service pointer.
+ * Note that the user is responsible for ensuring that the service pointer is valid as long
+ * as the service is registered in the Celix framework.
+ */
+ template<typename I>
+ ServiceRegistrationBuilder<I> registerUnmanagedService(I* svc, const std::string& name = {}) {
+ auto unmanagedSvc = std::shared_ptr<I>{svc, [](I*){/*nop*/}};
+ return ServiceRegistrationBuilder<I>{cCtx, std::move(unmanagedSvc), celix::typeName<I>(name)};
+ }
+
+ //TODO registerServiceFactory<I>()
+
+ /**
+ * Use a service registered in the Celix framework using a fluent builder API.
+ * The service use can be fine tuned using the returned UseServiceBuilder API.
+ *
+ * With this API a Celix service can be used by providing use functions.
+ * The use function will be executed on the Celix event thread and the Celix framework
+ * will ensure that the service cannot be removed while in use.
+ *
+ * If there are more 1 matching service, the highest ranking service will be used.
+ * If no service can be found the use callbacks with not be called.
+ *
+ *
+ * Example:
+ * shared_ptr<celix::BundleContext> ctx = ...
+ * auto callCount = ctx->useService<IExample>()
+ * .setTimeout(std::chrono::seconds{1})
+ * .addUseCallback([](IExample& service, const celix::Properties& props){
+ * std::cout << "Calling service with id " << props.get("service.id", "-1") << std::endl;
+ * service.method();
+ * })
+ * .build();
+ *
+ * @tparam I The service type to use
+ * @param name The optional service name to use. If not provided celix::typeName<I> will be used to defer the service name.
+ * @return A UseServiceBuilder object.
+ */
+ template<typename I>
+ UseServiceBuilder<I> useService(const std::string& name = {}) {
+ return UseServiceBuilder<I>{cCtx, celix::typeName<I>(name), true};
+ }
+
+ /**
+ * Use services registered in the Celix framework using a fluent builder API.
+ * The service use can be fine tuned using the returned UseServiceBuilder API.
+ *
+ * With this API Celix services can be used by providing use functions.
+ * The use function will be executed on the Celix event thread and the Celix framework
+ * will ensure that the service cannot be removed while in use.
+ *
+ * The use callbacks will be called for every matching service found.
+ *
+ * Example:
+ * shared_ptr<celix::BundleContext> ctx = ...
+ * auto callCount = ctx->useServices<IExample>()
+ * .addUseCallback([](IExample& service, const celix::Properties& props){
+ * std::cout << "Calling service with id " << props.get("service.id", "-1") << std::endl;
+ * service.method();
+ * })
+ * .build();
+ *
+ * @tparam I The service type to use
+ * @param name The optional service name to use. If not provided celix::typeName<I> will be used to defer the service name.
+ * @return A UseServiceBuilder object.
+ */
+ template<typename I>
+ UseServiceBuilder<I> useServices(const std::string& name = {}) {
+ return UseServiceBuilder<I>{cCtx, celix::typeName<I>(name), false};
+ }
+
+ /**
+ * Finds the highest ranking service using the optional provided (LDAP) filter
+ * and version range.
+ * Note uses celix::typeName<I> to defer the service name.
+ *
+ * @tparam I the service type to found.
+ * @param filter An optional LDAP filter.
+ * @param versionRange An optional version range.
+ * @return The service id of the found service or -1 if the service was not found.
+ */
+ template<typename I>
+ long findService(const std::string& filter = {}, const std::string& versionRange = {}) {
+ return findServiceWithName<I>(celix::typeName<I>(), filter, versionRange);
+ }
+
+ /**
+ * Finds the highest ranking service using the provided service name and
+ * the optional (LDAP) filter and version range.
+ *
+ * @tparam I the service type to found.
+ * @param The service name. (Can be empty to find service with any name).
+ * @param filter An optional LDAP filter.
+ * @param versionRange An optional version range.
+ * @return The service id of the found service or -1 if the service was not found.
+ */
+ template<typename I>
+ long findServiceWithName(const std::string& name, const std::string& filter = {}, const std::string& versionRange = {}) {
+ celix_service_filter_options_t opts{};
+ opts.serviceName = name.empty() ? nullptr : name.c_str();
+ opts.filter = filter.empty() ? nullptr : filter.c_str();
+ opts.versionRange = versionRange.empty() ? nullptr : versionRange.c_str();
+ return celix_bundleContext_findServiceWithOptions(cCtx.get(), &opts);
+ }
+
+ /**
+ * Finds all services matching the optional provided (LDAP) filter
+ * and version range.
+ * Note uses celix::typeName<I> to defer the service name.
+ *
+ * @tparam I the service type to found.
+ * @param filter An optional LDAP filter.
+ * @param versionRange An optional version range.
+ * @return A vector of service ids.
+ */
+ template<typename I>
+ std::vector<long> findServices(const std::string& filter = {}, const std::string& versionRange = {}) {
+ return findServicesWithName<I>(celix::typeName<I>(), filter, versionRange);
+ }
+
+ /**
+ * Finds all service matching the provided service name and the optional (LDAP) filter
+ * and version range.
+ *
+ * @tparam I the service type to found.
+ * @param The service name. (Can be empty to find service with any name).
+ * @param filter An optional LDAP filter.
+ * @param versionRange An optional version range.
+ * @return A vector of service ids.
+ */
+ template<typename I>
+ std::vector<long> findServicesWithName(const std::string& name, const std::string& filter = {}, const std::string& versionRange = {}) {
+ celix_service_filter_options_t opts{};
+ opts.serviceName = name.empty() ? nullptr : name.c_str();
+ opts.filter = filter.empty() ? nullptr : filter.c_str();
+ opts.versionRange = versionRange.empty() ? nullptr : versionRange.c_str();
+
+ std::vector<long> result{};
+ auto cList = celix_bundleContext_findServicesWithOptions(cCtx.get(), &opts);
+ for (int i = 0; i < celix_arrayList_size(cList); ++i) {
+ long svcId = celix_arrayList_getLong(cList, i);
+ result.push_back(svcId);
+ }
+ celix_arrayList_destroy(cList);
+ return result;
+ }
+
+ /**
+ * Track services in the Celix framework using a fluent builder API.
+ * The service tracker can be fine tuned using the returned ServiceTrackerBuilder API.
+ *
+ * Example:
+ * shared_ptr<celix::BundleContext> ctx = ...
+ * auto tracker = ctx->trackServices<IExample>()
+ * .setFilter("(property_key=value)")
+ * .addAddCallback([](std::shared_ptr<IExample>, std::shared_ptr<const celix::Properties> props) {
+ * std::cout << "Adding service with id '" << props->get("service.id", "-1") << std::endl;
+ * })
+ * .addRemCallback([](std::shared_ptr<IExample>, std::shared_ptr<const celix::Properties> props) {
+ * std::cout << "Removing service with id '" << props->get("service.id", "-1") << std::endl;
+ * })
+ * .build();
+ *
+ * @tparam I The service type to track
+ * @param name The optional service name. If empty celix::typeName<I> will be used to defer the service name.
+ * @return A ServiceTrackerBuilder object.
+ */
+ template<typename I>
+ ServiceTrackerBuilder<I> trackServices(const std::string& name = {}) {
+ return ServiceTrackerBuilder<I>{cCtx, celix::typeName<I>(name)};
+ }
+
+ /**
+ * Same as trackerService, but than for any service.
+ * Note that the service shared ptr is of the type std::shared_ptr<void>.
+ */
+ ServiceTrackerBuilder<void> trackAnyServices() {
+ return ServiceTrackerBuilder<void>{cCtx, {}};
+ }
+
+ /**
+ * Track bundles in the Celix framework using a fluent builder API.
+ * The bundle tracker can be fine tuned using the returned BundleTrackerBuilder API.
+ *
+ * Example:
+ * shared_ptr<celix::BundleContext> ctx = ...
+ * auto tracker = ctx->trackBundles<>()
+ * .addOnInstallCallback([](const celix::Bundle& bnd) {
+ * std::cout << "Bundle installed with id '" << bnd.getId() << std::endl;
+ * })
+ * .build();
+ *
+ * @return A BundleTrackerBuilder object.
+ */
+ BundleTrackerBuilder trackBundles() {
+ return BundleTrackerBuilder{cCtx};
+ }
+
+ /**
+ * Track service trackers in the Celix framework using a fluent builder API.
+ * The meta tracker (service tracker tracker) can be fine tuned using the returned
+ * MetaTrackerBuilder API.
+ *
+ * Example:
+ * shared_ptr<celix::BundleContext> ctx = ...
+ * auto tracker = ctx->trackServiceTrackers<IExample>()
+ * .addOnTrackerCreatedCallback([](const ServiceTrackerInfo& info) {
+ * std::cout << "Tracker created for service name '" << info.serviceName << std::endl;
+ * })
+ * .addOnTrackerDestroyedCallback([](const ServiceTrackerInfo& info) {
+ * std::cout << "Tracker destroyed for service name '" << info.serviceName << std::endl;
+ * })
+ * .build();
+ *
+ * @tparam I The service tracker service type to track.
+ * @param name The optional service name. If empty celix::typeName<I> will be used to defer the service name.
+ * @return A MetaTrackerBuilder object.
+ */
+ template<typename I>
+ MetaTrackerBuilder trackServiceTrackers(const std::string& name = {}) {
+ return MetaTrackerBuilder(cCtx, celix::typeName<I>(name));
+ }
+
+ /**
+ * Same as trackServiceTrackers, but than for service tracker for any service types.
+ */
+ MetaTrackerBuilder trackAnyServiceTrackers() {
+ return MetaTrackerBuilder(cCtx, {});
+ }
+
+ /**
+ * Install and optional start a bundle.
+ * Will silently ignore bundle ids < 0.
+ *
+ * @param bndLocation The bundle location to the bundle zip file.
+ * @param autoStart If the bundle should also be started.
+ * @return the bundleId (>= 0) or < 0 if the bundle could not be installed and possibly started.
+ */
+ long installBundle(const std::string& bndLocation, bool autoStart = true) {
+ return celix_bundleContext_installBundle(cCtx.get(), bndLocation.c_str(), autoStart);
+ }
+
+ /**
+ * Uninstall the bundle with the provided bundle id. If needed the bundle will be stopped first.
+ * Will silently ignore bundle ids < 0.
+ *
+ * @param bndId The bundle id to uninstall.
+ * @return true if the bundle is correctly uninstalled. False if not.
+ */
+ bool uninstallBundle(long bndId) {
+ return celix_bundleContext_uninstallBundle(cCtx.get(), bndId);
+ }
+
+ /**
+ * Start the bundle with the provided bundle id.
+ * Will silently ignore bundle ids < 0.
+ *
+ * @param bndId The bundle id to start.
+ * @return true if the bundle is found & correctly started. False if not.
+ */
+ bool startBundle(long bndId) {
+ return celix_bundleContext_startBundle(cCtx.get(), bndId);
+ }
+
+ /**
+ * Stop the bundle with the provided bundle id.
+ * Will silently ignore bundle ids < 0.
+ *
+ * @param bndId The bundle id to stop.
+ * @return true if the bundle is found & correctly stop. False if not.
+ */
+ bool stopBundle(long bndId) {
+ return celix_bundleContext_stopBundle(cCtx.get(), bndId);
+ }
+
+ /**
+ * Gets the config property - or environment variable if the config property does not exist - for the provided name.
+ * @param name The name of the property to receive.
+ * @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 {
+ return std::string{celix_bundleContext_getProperty(cCtx.get(), name.c_str(), defaultValue.c_str())};
+ }
+
+ /**
+ * Gets the config property - or environment variable if the config property does not exist - for the provided name.
+ * Only returns the value if it is a valid long.
+ *
+ * @param name The name of the property to receive.
+ * @param defaultVal The default value to use if the property is not found.
+ * @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 {
+ return celix_bundleContext_getPropertyAsLong(cCtx.get(), name.c_str(), defaultValue);
+ }
+
+ /**
+ * Gets the config property - or environment variable if the config property does not exist - for the provided name.
+ * Only returns the value if it is a valid double.
+ *
+ * @param name The name of the property to receive.
+ * @param defaultVal The default value to use if the property is not found.
+ * @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 {
+ return celix_bundleContext_getPropertyAsDouble(cCtx.get(), name.c_str(), defaultValue);
+ }
+
+ /**
+ * Gets the config property - or environment variable if the config property does not exist - for the provided name.
+ * Only returns the value if it is a valid boolean.
+ *
+ * @param name The name of the property to receive.
+ * @param defaultVal The default value to use if the property is not found.
+ * @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 {
+ return celix_bundleContext_getPropertyAsBool(cCtx.get(), name.c_str(), defaultValue);
+ }
+
+ /**
+ * Get the bundle of this bundle context.
+ */
+ const Bundle& getBundle() const {
+ return bnd;
+ }
+
+ /**
+ * Get the Celix framework for this bundle context.
+ */
+ 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);
+ }
+
+ /**
+ * Get the Celix dependency manager for this bundle context
+ */
+ std::shared_ptr<dm::DependencyManager> getDependencyManager() const {
+ return dm;
+ }
+
+ /**
+ * Get the C bundle context.
+ */
+ celix_bundle_context_t* getCBundleContext() const {
+ return cCtx.get();
+ }
+
+ /**
+ * Logs a message to the Celix framework logger using the TRACE log level.
+ * NOTE only supports printf style call (so use c_str() instead of std::string)
+ */
+ void logTrace(const char* format...) {
+ va_list args;
+ va_start(args, format);
+ celix_bundleContext_vlog(cCtx.get(), CELIX_LOG_LEVEL_TRACE, format, args);
+ va_end(args);
+ }
+
+ /**
+ * Logs a message to the Celix framework logger using the DEBUG log level.
+ * NOTE only supports printf style call (so use c_str() instead of std::string)
+ */
+ void logDebug(const char* format...) {
+ va_list args;
+ va_start(args, format);
+ celix_bundleContext_vlog(cCtx.get(), CELIX_LOG_LEVEL_DEBUG, format, args);
+ va_end(args);
+ }
+
+ /**
+ * Logs a message to the Celix framework logger using the INFO log level.
+ * NOTE only supports printf style call (so use c_str() instead of std::string)
+ */
+ void logInfo(const char* format...) {
+ va_list args;
+ va_start(args, format);
+ celix_bundleContext_vlog(cCtx.get(), CELIX_LOG_LEVEL_INFO, format, args);
+ va_end(args);
+ }
+
+ /**
+ * Logs a message to the Celix framework logger using the WARNING log level.
+ * NOTE only supports printf style call (so use c_str() instead of std::string)
+ */
+ void logWarn(const char* format...) {
+ va_list args;
+ va_start(args, format);
+ celix_bundleContext_vlog(cCtx.get(), CELIX_LOG_LEVEL_WARNING, format, args);
+ va_end(args);
+ }
+
+ /**
+ * Logs a message to the Celix framework logger using the ERROR log level.
+ * NOTE only supports printf style call (so use c_str() instead of std::string)
+ */
+ void logError(const char* format...) {
+ va_list args;
+ va_start(args, format);
+ celix_bundleContext_vlog(cCtx.get(), CELIX_LOG_LEVEL_ERROR, format, args);
+ va_end(args);
+ }
+
+ /**
+ * Logs a message to the Celix framework logger using the FATAL log level.
+ * NOTE only supports printf style call (so use c_str() instead of std::string)
+ */
+ void logFatal(const char* format...) {
+ va_list args;
+ va_start(args, format);
+ celix_bundleContext_vlog(cCtx.get(), CELIX_LOG_LEVEL_FATAL, format, args);
+ va_end(args);
+ }
+
+ private:
+ const std::shared_ptr<celix_bundle_context_t> cCtx;
+ const std::shared_ptr<celix::dm::DependencyManager> dm;
+ const Bundle bnd;
+ };
+}
+
+
diff --git a/libs/framework/include/celix/Constants.h b/libs/framework/include/celix/Constants.h
new file mode 100644
index 0000000..d80a719
--- /dev/null
+++ b/libs/framework/include/celix/Constants.h
@@ -0,0 +1,40 @@
+/*
+ * 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 "celix_constants.h"
+
+namespace celix {
+
+ constexpr const char * const SERVICE_NAME = OSGI_FRAMEWORK_OBJECTCLASS;
+ constexpr const char * const SERVICE_ID = OSGI_FRAMEWORK_SERVICE_ID;
+ constexpr const char * const SERVICE_PID = OSGI_FRAMEWORK_SERVICE_PID;
+
+ constexpr const char * const SERVICE_RANKING = OSGI_FRAMEWORK_SERVICE_RANKING;
+ constexpr const char * const SERVICE_VERSION = CELIX_FRAMEWORK_SERVICE_VERSION;
+
+ constexpr const char * const FRAMEWORK_STORAGE = OSGI_FRAMEWORK_FRAMEWORK_STORAGE;
+ constexpr const char * const FRAMEWORK_STORAGE_USE_TMP_DIR = OSGI_FRAMEWORK_STORAGE_USE_TMP_DIR;
+ constexpr const char * const FRAMEWORK_UUID = OSGI_FRAMEWORK_FRAMEWORK_UUID;
+
+ constexpr const char * const BUNDLES_PATH_NAME = CELIX_BUNDLES_PATH_NAME;
+
+ constexpr const char * const LOAD_BUNDLES_WITH_NODELETE = CELIX_LOAD_BUNDLES_WITH_NODELETE;
+}
\ No newline at end of file
diff --git a/libs/framework/include/celix/Filter.h b/libs/framework/include/celix/Filter.h
new file mode 100644
index 0000000..de00f48
--- /dev/null
+++ b/libs/framework/include/celix/Filter.h
@@ -0,0 +1,91 @@
+/*
+ * 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 <memory>
+
+#include "celix/Properties.h"
+#include "celix_filter.h"
+
+namespace celix {
+
+ /**
+ * TODO
+ * \note Not thread safe.
+ */
+ class Filter {
+ public:
+ Filter() : cFilter{createFilter("")} {}
+ explicit Filter(const std::string& filterStr) : cFilter{createFilter(filterStr)} {}
+
+ Filter(Filter&&) = default;
+ Filter& operator=(Filter&&) = default;
+
+ Filter(const Filter& rhs) : cFilter{createFilter(rhs.getFilterString())} {}
+
+ Filter& operator=(const Filter& rhs) {
+ if (this != &rhs) {
+ cFilter = createFilter(rhs.getFilterString());
+ }
+ return *this;
+ }
+
+ //warning no ownership
+ static Filter wrap(celix_filter_t* f) {
+ return Filter{f};
+ }
+
+ std::string getFilterString() const {
+ auto cStr = celix_filter_getFilterString(cFilter.get());
+ return cStr == nullptr ? std::string{} : std::string{cStr};
+ }
+
+ bool match(const celix::Properties& props) const {
+ return celix_filter_match(cFilter.get(), props.getCProperties());
+ }
+
+ 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};
+ }
+
+ bool hasAttribute(const std::string& attributeKey) const {
+ return celix_filter_findAttribute(cFilter.get(), attributeKey.c_str()) != nullptr;
+ }
+
+ celix_filter_t* getCFilter() const {
+ return cFilter.get();
+ }
+ private:
+ static std::shared_ptr<celix_filter_t> createFilter(const std::string& filterStr) {
+ auto *cf = celix_filter_create(filterStr.c_str());
+ if (cf == nullptr) {
+ throw std::logic_error{"TODO create and throw celix (filter?) error. Invalid filter: '" + filterStr + "'"};
+ }
+ return std::shared_ptr<celix_filter_t>{cf, [](celix_filter_t *f) {
+ celix_filter_destroy(f);
+ }};
+ }
+
+ explicit Filter(celix_filter_t* f) : cFilter{f, [](celix_filter_t*){/*nop*/}} {}
+
+ std::shared_ptr<celix_filter_t> cFilter;
+ };
+}
\ No newline at end of file
diff --git a/examples/celix-examples/hello_world_cxx/src/BundleActivator.cc b/libs/framework/include/celix/Framework.h
similarity index 50%
copy from examples/celix-examples/hello_world_cxx/src/BundleActivator.cc
copy to libs/framework/include/celix/Framework.h
index 2921ba7..777565c 100644
--- a/examples/celix-examples/hello_world_cxx/src/BundleActivator.cc
+++ b/libs/framework/include/celix/Framework.h
@@ -17,29 +17,42 @@
* under the License.
*/
+#pragma once
+
#include <memory>
-#include <iostream>
-#include <celix_api.h>
+#include "celix_framework.h"
+
+namespace celix {
-namespace /*anon*/ {
+ class BundleContext; //forward declaration
- class BundleActivator {
+ /**
+ * TODO
+ * \note Thread safe.
+ */
+ class Framework {
public:
- BundleActivator(std::shared_ptr<celix::dm::DependencyManager> _mng) : mng{std::move(_mng)} {
- std::cout << "Hello world from C++ bundle with id " << bndId() << std::endl;
+ Framework(std::shared_ptr<celix::BundleContext> _fwCtx, celix_framework_t* _cFw) :
+ fwCtx{std::move(_fwCtx)},
+ cFw{std::shared_ptr<celix_framework_t >{_cFw, [](celix_framework_t*){/*nop*/}}}
+ {}
+
+ /**
+ * Get the framework UUID.
+ */
+ std::string getUUID() const {
+ return std::string{celix_framework_getUUID(cFw.get())};
}
- ~BundleActivator() {
- std::cout << "Goodbye world from C++ bundle with id " << bndId() << std::endl;
+
+ /**
+ * Get the bundle context for the framework.
+ */
+ std::shared_ptr<celix::BundleContext> getFrameworkBundleContext() const {
+ return fwCtx;
}
private:
- long bndId() const {
- return celix_bundle_getId(celix_bundleContext_getBundle(mng->bundleContext()));
- }
-
- std::shared_ptr<celix::dm::DependencyManager> mng;
+ const std::shared_ptr<celix::BundleContext> fwCtx;
+ const std::shared_ptr<celix_framework_t> cFw;
};
-
-}
-
-CELIX_GEN_CXX_BUNDLE_ACTIVATOR(BundleActivator)
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/libs/framework/include/celix/Properties.h b/libs/framework/include/celix/Properties.h
new file mode 100644
index 0000000..c0c587b
--- /dev/null
+++ b/libs/framework/include/celix/Properties.h
@@ -0,0 +1,217 @@
+/*
+ * 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 <map>
+#include <unordered_map>
+#include <memory>
+
+#include "celix_properties.h"
+#include "utils.h"
+#include "hash_map.h"
+
+namespace celix {
+
+ class PropertiesIterator {
+ public:
+ explicit PropertiesIterator(celix_properties_t* props) : iter{hashMapIterator_construct((hash_map_t*)props)} { next(); }
+ explicit PropertiesIterator(const celix_properties_t* props) : iter{hashMapIterator_construct((hash_map_t*)props)} { next(); }
+
+ PropertiesIterator& operator++() {
+ next();
+ return *this;
+ }
+
+ PropertiesIterator& operator*() {
+ return *this;
+ }
+
+ bool operator==(const celix::PropertiesIterator& rhs) const {
+ bool sameMap = iter.map == rhs.iter.map;
+ bool sameIndex = iter.index == rhs.iter.index;
+ bool oneIsEnd = end || rhs.end;
+ if (oneIsEnd) {
+ return sameMap && end && rhs.end;
+ } else {
+ return sameMap && sameIndex;
+ }
+ }
+
+ bool operator!=(const celix::PropertiesIterator& rhs) const {
+ return !operator==(rhs);
+ }
+
+ void next() {
+ if (hashMapIterator_hasNext(&iter)) {
+ auto* entry = hashMapIterator_nextEntry(&iter);
+ auto *k = hashMapEntry_getKey(entry);
+ auto *v = hashMapEntry_getValue(entry);
+ first = std::string{(const char*)k};
+ second = std::string{(const char*)v};
+ } else {
+ moveToEnd();
+ }
+ }
+
+ void moveToEnd() {
+ end = true;
+ first = {};
+ second = {};
+ }
+
+ std::string first{};
+ std::string second{};
+ private:
+ hash_map_iterator_t iter;
+ bool end{false};
+ };
+
+ /**
+ * TODO
+ * \warning Not thread safe.
+ */
+ class Properties {
+ public:
+ using const_iterator = PropertiesIterator;
+
+ class ValueRef {
+ public:
+ ValueRef(std::shared_ptr<celix_properties_t> _props, std::string _key) : props{std::move(_props)}, key{std::move(_key)} {}
+ ValueRef& operator=(const std::string& value) {
+ celix_properties_set(props.get(), key.c_str(), value.c_str());
+ return *this;
+ }
+
+ const char* getValue() const {
+ return celix_properties_get(props.get(), key.c_str(), nullptr);
+ }
+
+ operator std::string() const {
+ auto *cstr = getValue();
+ return cstr == nullptr ? std::string{} : std::string{cstr};
+ }
+ private:
+ std::shared_ptr<celix_properties_t> props;
+ std::string key;
+ };
+
+
+ Properties() : cProps{celix_properties_create(), [](celix_properties_t* p) { celix_properties_destroy(p); }} {}
+
+ Properties(Properties&&) = default;
+ Properties& operator=(Properties&&) = default;
+
+ Properties& operator=(const Properties &rhs) {
+ if (this != &rhs) {
+ cProps = std::shared_ptr<celix_properties_t>{celix_properties_copy(rhs.cProps.get()), [](celix_properties_t* p) { celix_properties_destroy(p); }};
+ }
+ return *this;
+ }
+
+ Properties(const Properties& rhs) :
+ cProps{celix_properties_copy(rhs.cProps.get()), [](celix_properties_t* p) { celix_properties_destroy(p); }} {}
+
+ /**
+ * Wraps C properties, but does not take ownership -> dtor will not destroy properties
+ */
+ static std::shared_ptr<const Properties> wrap(const celix_properties_t* wrapProps) {
+ auto* cp = const_cast<celix_properties_t*>(wrapProps);
+ return std::shared_ptr<const Properties>{new Properties{cp}};
+ }
+
+ celix_properties_t* getCProperties() const {
+ return cProps.get();
+ }
+
+ ValueRef operator[](std::string key) {
+ return ValueRef{cProps, std::move(key)};
+ }
+
+ const_iterator begin() const noexcept {
+ return PropertiesIterator{cProps.get()};
+ }
+
+ const_iterator end() const noexcept {
+ auto iter = PropertiesIterator{cProps.get()};
+ iter.moveToEnd();
+ return iter;
+ }
+
+ const_iterator cbegin() const noexcept {
+ return PropertiesIterator{cProps.get()};
+ }
+
+ const_iterator cend() const noexcept {
+ auto iter = PropertiesIterator{cProps.get()};
+ iter.moveToEnd();
+ return iter;
+ }
+
+ 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};
+ }
+
+ long getAsLong(const std::string& key, long defaultValue) const {
+ return celix_properties_getAsLong(cProps.get(), key.c_str(), defaultValue);
+ }
+
+ double getAsDouble(const std::string &key, double defaultValue) const {
+ return celix_properties_getAsDouble(cProps.get(), key.c_str(), defaultValue);
+ }
+
+ bool getAsBool(const std::string &key, bool defaultValue) const {
+ return celix_properties_getAsBool(cProps.get(), key.c_str(), defaultValue);
+ }
+
+ void set(const std::string& key, const std::string& value) {
+ celix_properties_set(cProps.get(), key.c_str(), value.c_str());
+ }
+
+ void set(const std::string& key, const char* value) {
+ celix_properties_set(cProps.get(), key.c_str(), value);
+ }
+
+ void set(const std::string& key, bool value) {
+ celix_properties_setBool(cProps.get(), key.c_str(), value);
+ }
+
+ template<typename T>
+ void set(const std::string& key, T value) {
+ using namespace std;
+ celix_properties_set(cProps.get(), key.c_str(), to_string(value).c_str());
+ }
+
+ std::size_t size() const {
+ return celix_properties_size(cProps.get());
+ }
+ private:
+ explicit Properties(celix_properties_t* props) : cProps{props, [](celix_properties_t*) { /*nop*/ }} {}
+
+ std::shared_ptr<celix_properties_t> cProps;
+ };
+
+}
+
+inline std::ostream& operator<<(std::ostream& os, const ::celix::Properties::ValueRef& ref)
+{
+ os << std::string{ref.getValue()}; //TODO improve
+ return os;
+}
\ No newline at end of file
diff --git a/libs/framework/include/celix/dm/Properties.h b/libs/framework/include/celix/ServiceFactory.h
similarity index 67%
copy from libs/framework/include/celix/dm/Properties.h
copy to libs/framework/include/celix/ServiceFactory.h
index 5c33885..8f561c4 100644
--- a/libs/framework/include/celix/dm/Properties.h
+++ b/libs/framework/include/celix/ServiceFactory.h
@@ -19,9 +19,18 @@
#pragma once
-#include <map>
-#include <string>
+#include "celix/Bundle.h"
+#include "celix/Properties.h"
-namespace celix { namespace dm {
- using Properties = std::map<std::string, std::string>;
-}}
+namespace celix {
+
+ template<typename I>
+ class ServiceFactory {
+ public:
+ virtual ~ServiceFactory() = default;
+
+ virtual std::shared_ptr<I> createBundleSpecificService(const celix::Bundle& requestingBundle, const celix::Properties svcFactoryProperties) = 0;
+ //TODO,TBD need ungetService variant?
+ };
+
+}
\ No newline at end of file
diff --git a/libs/framework/include/celix/ServiceRegistration.h b/libs/framework/include/celix/ServiceRegistration.h
new file mode 100644
index 0000000..1a2cd02
--- /dev/null
+++ b/libs/framework/include/celix/ServiceRegistration.h
@@ -0,0 +1,176 @@
+/*
+ * 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 <memory>
+#include <mutex>
+#include <vector>
+#include <functional>
+
+#include "celix/Properties.h"
+#include "celix_bundle_context.h"
+
+namespace celix {
+
+ enum class ServiceRegistrationState {
+ REGISTERING,
+ REGISTERED,
+ UNREGISTERING,
+ UNREGISTERED
+ };
+
+ class ServiceRegistration;
+
+ /**
+ * TODO
+ * \note Thread safe.
+ */
+ class ServiceRegistration {
+ public:
+ ServiceRegistration(
+ std::shared_ptr<celix_bundle_context_t> _cCtx,
+ std::shared_ptr<void> _svc,
+ std::string _name,
+ std::string _version,
+ celix::Properties _properties,
+ std::vector<std::function<void(const std::shared_ptr<ServiceRegistration>&)>> _onRegisteredCallbacks,
+ std::vector<std::function<void(const std::shared_ptr<ServiceRegistration>&)>> _onUnregisteredCallbacks) :
+ cCtx{std::move(_cCtx)},
+ svc{std::move(_svc)},
+ name{std::move(_name)},
+ version{std::move(_version)},
+ properties{std::move(_properties)},
+ onRegisteredCallbacks{std::move(_onRegisteredCallbacks)},
+ onUnregisteredCallbacks{std::move(_onUnregisteredCallbacks)} {
+
+ //setup registration using C api.
+ auto* cProps = celix_properties_copy(properties.getCProperties());
+ celix_service_registration_options_t opts{};
+ opts.svc = svc.get();
+ opts.serviceName = name.c_str();
+ opts.properties = cProps;
+ if (!version.empty()) {
+ opts.serviceVersion = version.c_str();
+ }
+ opts.asyncData = static_cast<void*>(this);
+ opts.asyncCallback = [](void *data, long /*svcId*/) {
+ auto *reg = static_cast<ServiceRegistration *>(data);
+ {
+ std::lock_guard<std::mutex> lck{reg->mutex};
+ reg->state = ServiceRegistrationState::REGISTERED;
+ }
+ auto regAsSharedPtr = reg->getSelf();
+ for (const auto &cb : reg->onRegisteredCallbacks) {
+ cb(regAsSharedPtr);
+ }
+ };
+ std::lock_guard<std::mutex> lck{mutex};
+ svcId = celix_bundleContext_registerServiceWithOptionsAsync(cCtx.get(), &opts);
+ }
+
+ ~ServiceRegistration() noexcept {
+ wait(); //if state is REGISTERING, wait till registration is complete.
+ unregister(); //if state is REGISTERED, queue unregistration.
+ wait(); //if state is UNREGISTERING, wait till unregistration is complete.
+ }
+
+ const std::string& getServiceName() const { return name; }
+ const std::string& getServiceVersion() const { return version; }
+ const celix::Properties& getServiceProperties() const { return properties; }
+
+ ServiceRegistrationState getCurrentState() const {
+ std::lock_guard<std::mutex> lck{mutex};
+ return state;
+ }
+
+ long getServiceId() const {
+ std::lock_guard<std::mutex> lck{mutex};
+ return svcId;
+ }
+
+ void wait() const {
+ bool needWaitUnregistering = false;
+ bool needWaitRegistering = false;
+ long localId;
+ {
+ std::lock_guard<std::mutex> lck{mutex};
+ localId = svcId;
+ if (state == ServiceRegistrationState::REGISTERING) {
+ needWaitRegistering = true;
+ } else if (state == ServiceRegistrationState::UNREGISTERING) {
+ needWaitUnregistering = true;
+ }
+ }
+ if (needWaitRegistering) {
+ celix_bundleContext_waitForAsyncRegistration(cCtx.get(), localId);
+ }
+ if (needWaitUnregistering) {
+ celix_bundleContext_waitForAsyncUnregistration(cCtx.get(), localId);
+ }
+ }
+
+ void unregister() {
+ wait(); //if state is REGISTERING, wait till registration is complete.
+ std::lock_guard<std::mutex> lck{mutex};
+ if (state == ServiceRegistrationState::REGISTERED) {
+ //not yet unregistering
+ state = ServiceRegistrationState::UNREGISTERING;
+
+ //NOTE: As long this unregister event is in the queue, the ServiceRegistration will wait in its dtor
+ celix_bundleContext_unregisterServiceAsync(cCtx.get(), svcId, this, [](void *data) {
+ auto reg = static_cast<ServiceRegistration*>(data);
+ {
+ std::lock_guard<std::mutex> lck{reg->mutex};
+ reg->state = ServiceRegistrationState::UNREGISTERED;
+ }
+ auto regAsSharedPtr = reg->getSelf();
+ for (const auto &cb : reg->onUnregisteredCallbacks) {
+ cb(regAsSharedPtr);
+ }
+ });
+ }
+ }
+
+ void setSelf(const std::shared_ptr<ServiceRegistration>& s) {
+ std::lock_guard<std::mutex> lck{mutex};
+ self = s;
+ }
+
+ std::shared_ptr<ServiceRegistration> getSelf() const {
+ std::lock_guard<std::mutex> lck{mutex};
+ return self.lock();
+ }
+
+ private:
+ const std::shared_ptr<celix_bundle_context_t> cCtx;
+ const std::shared_ptr<void> svc;
+ const std::string name;
+ const std::string version;
+ const celix::Properties properties;
+ const std::vector<std::function<void(const std::shared_ptr<ServiceRegistration>&)>> onRegisteredCallbacks;
+ const std::vector<std::function<void(const std::shared_ptr<ServiceRegistration>&)>> onUnregisteredCallbacks;
+
+ mutable std::mutex mutex{}; //protects below
+ long svcId{-1};
+ ServiceRegistrationState state{ServiceRegistrationState::REGISTERING};
+ std::weak_ptr<ServiceRegistration> self{}; //weak ptr to self, so that callbacks can receive a shared ptr
+ };
+
+}
\ No newline at end of file
diff --git a/libs/framework/include/celix/Trackers.h b/libs/framework/include/celix/Trackers.h
new file mode 100644
index 0000000..e2a6b70
--- /dev/null
+++ b/libs/framework/include/celix/Trackers.h
@@ -0,0 +1,481 @@
+/*
+ * 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 <memory>
+#include <mutex>
+#include <atomic>
+#include <cassert>
+
+#include "celix/Properties.h"
+#include "celix/Utils.h"
+#include "celix/Bundle.h"
+#include "celix/Constants.h"
+#include "celix/Filter.h"
+#include "celix_bundle_context.h"
+
+namespace celix {
+
+ /**
+ * TODO
+ * GenericTracker <-----------------------------------
+ * ^ | |
+ * | | |
+ * GenericServiceTracker BundleTracker MetaTracker
+ * ^
+ * |
+ * ServiceTracker<I>
+ */
+
+ enum class TrackerState {
+ OPENING,
+ OPEN,
+ CLOSING,
+ CLOSED
+ };
+
+ /**
+ * TODO
+ * \note Thread safe.
+ */
+ class AbstractTracker {
+ public:
+ explicit AbstractTracker(std::shared_ptr<celix_bundle_context_t> _cCtx) : cCtx{std::move(_cCtx)} {}
+
+ virtual ~AbstractTracker() noexcept {
+ //NOTE that the tracker needs to be closed in the specialization (when all fields are still valid)
+ assert(getCurrentState() == TrackerState::CLOSED);
+ }
+
+ bool isOpen() const {
+ std::lock_guard<std::mutex> lck{mutex};
+ return state == TrackerState::OPEN;
+ }
+
+ TrackerState getCurrentState() const {
+ std::lock_guard<std::mutex> lck{mutex};
+ return state;
+ }
+
+ void close() {
+ wait(); //if state is OPENING, wait till tracker is opened
+ std::lock_guard<std::mutex> lck{mutex};
+ if (state == TrackerState::OPEN) {
+ //not yet closed
+ state = TrackerState::CLOSING;
+
+ celix_bundleContext_stopTrackerAsync(cCtx.get(), trkId, this, [](void *data) {
+ auto trk = static_cast<AbstractTracker*>(data);
+ std::lock_guard<std::mutex> lck{trk->mutex};
+ trk->state = TrackerState::CLOSED;
+ trk->trkId = -1L;
+ });
+ }
+ }
+
+ //note needs override, open is different per tracker type
+ virtual void open() {}
+
+ void wait() const {
+ bool needWaitOpening = false;
+ bool needWaitClosing = false;
+ long localId;
+ {
+ std::lock_guard<std::mutex> lck{mutex};
+ localId = trkId;
+ if (state == TrackerState::OPENING) {
+ needWaitOpening = true;
+ } else if (state == TrackerState::CLOSING) {
+ needWaitClosing = true;
+ }
+ }
+ if (needWaitOpening) {
+ celix_bundleContext_waitForAsyncTracker(cCtx.get(), localId);
+ }
+ if (needWaitClosing) {
+ celix_bundleContext_waitForAsyncStopTracker(cCtx.get(), localId);
+ }
+ }
+ protected:
+ const std::shared_ptr<celix_bundle_context_t> cCtx;
+ mutable std::mutex mutex{}; //protects below
+ long trkId{-1L};
+ TrackerState state{TrackerState::CLOSED};
+ };
+
+ /**
+ * TODO
+ * \note Thread safe.
+ */
+ class GenericServiceTracker : public AbstractTracker {
+ public:
+ GenericServiceTracker(std::shared_ptr<celix_bundle_context_t> _cCtx, std::string _svcName,
+ std::string _svcVersionRange, std::string _filter) : AbstractTracker{std::move(_cCtx)}, svcName{std::move(_svcName)},
+ svcVersionRange{std::move(_svcVersionRange)}, filter{std::move(_filter)} {
+ opts.trackerCreatedCallbackData = this;
+ opts.trackerCreatedCallback = [](void *data) {
+ auto* trk = static_cast<GenericServiceTracker*>(data);
+ std::lock_guard<std::mutex> callbackLock{trk->mutex};
+ trk->state = TrackerState::OPEN;
+ };
+ }
+
+ ~GenericServiceTracker() override = default;
+
+ void open() override {
+ wait(); //if state is CLOSING, wait till tracker is closed
+ std::lock_guard<std::mutex> lck{mutex};
+ if (state == TrackerState::CLOSED) {
+ state = TrackerState::OPENING;
+
+ //NOTE assuming the opts already configured the callbacks
+ trkId = celix_bundleContext_trackServicesWithOptionsAsync(cCtx.get(), &opts);
+ }
+ }
+
+ const std::string& getServiceName() const { return svcName; }
+
+ const std::string& getServiceRange() const { return svcVersionRange; }
+
+ const std::string& getFilter() const { return filter; }
+
+ std::size_t getServiceCount() const {
+ return svcCount;
+ }
+ protected:
+ const std::string svcName;
+ const std::string svcVersionRange;
+ const std::string filter;
+ celix_service_tracking_options opts{}; //note only set in the ctor
+ std::atomic<size_t> svcCount{0};
+ };
+
+ /**
+ * \note Thread safe.
+ * @tparam I The service type to track
+ */
+ template<typename I>
+ class ServiceTracker : public GenericServiceTracker {
+ public:
+ ServiceTracker(std::shared_ptr<celix_bundle_context_t> _cCtx, std::string _svcName,
+ std::string _svcVersionRange, std::string _filter,
+ std::vector<std::function<void(std::shared_ptr<I>, std::shared_ptr<const celix::Properties>, std::shared_ptr<const celix::Bundle>)>> _setCallbacks,
+ std::vector<std::function<void(std::shared_ptr<I>, std::shared_ptr<const celix::Properties>, const celix::Bundle&)>> _addCallbacks,
+ std::vector<std::function<void(std::shared_ptr<I>, std::shared_ptr<const celix::Properties>, const celix::Bundle&)>> _remCallbacks) :
+ GenericServiceTracker{std::move(_cCtx), std::move(_svcName), std::move(_svcVersionRange), std::move(_filter)},
+ setCallbacks{std::move(_setCallbacks)},
+ addCallbacks{std::move(_addCallbacks)},
+ remCallbacks{std::move(_remCallbacks)} {
+
+ opts.filter.serviceName = svcName.empty() ? nullptr : svcName.c_str();
+ opts.filter.versionRange = svcVersionRange.empty() ? nullptr : svcVersionRange.c_str();
+ opts.filter.filter = filter.empty() ? nullptr : filter.c_str();
+ opts.callbackHandle = this;
+ opts.addWithOwner = [](void *handle, void *voidSvc, const celix_properties_t* cProps, const celix_bundle_t* cBnd) {
+ auto tracker = static_cast<ServiceTracker<I>*>(handle);
+ long svcId = celix_properties_getAsLong(cProps, OSGI_FRAMEWORK_SERVICE_ID, -1L);
+ auto svc = tracker->getServiceForId(svcId, voidSvc);
+ auto props = tracker->getPropertiesForId(svcId, cProps);
+ //TODO auto bnd = tracker->getBundleForId(svcId, cBnd);
+ auto bnd = celix::Bundle{const_cast<celix_bundle_t*>(cBnd)};
+ for (const auto& func : tracker->addCallbacks) {
+ func(svc, props, bnd);
+ }
+ tracker->svcCount.fetch_add(1, std::memory_order_relaxed);
+ };
+ opts.removeWithOwner = [](void *handle, void *voidSvc, const celix_properties_t* cProps, const celix_bundle_t* cBnd) {
+ auto tracker = static_cast<ServiceTracker<I>*>(handle);
+ long svcId = celix_properties_getAsLong(cProps, OSGI_FRAMEWORK_SERVICE_ID, -1L);
+ auto svc = tracker->getServiceForId(svcId, voidSvc);
+ auto props = tracker->getPropertiesForId(svcId, cProps);
+ //TODO auto bnd = tracker->getBundleForId(svcId, cBnd);
+ auto bnd = celix::Bundle{const_cast<celix_bundle_t*>(cBnd)};
+ for (const auto& func : tracker->remCallbacks) {
+ func(svc, props, bnd);
+ }
+ tracker->svcCount.fetch_sub(1, std::memory_order_relaxed);
+
+ tracker->removeAddRemEntriesForId(svcId);
+ tracker->waitForExpire(std::move(svc), svcId, "Service");
+ tracker->waitForExpire(std::move(props), svcId, "celix::Properties");
+ };
+ opts.setWithOwner = [](void *handle, void *voidSvc, const celix_properties_t* cProps, const celix_bundle_t* cBnd) {
+ auto tracker = static_cast<ServiceTracker<I>*>(handle);
+ std::shared_ptr<I> svc{};
+ std::shared_ptr<const celix::Properties> props{};
+ std::shared_ptr<const celix::Bundle> bnd{};
+ if (voidSvc != nullptr) {
+ svc = std::shared_ptr<I>{static_cast<I*>(voidSvc), [](I*){/*nop*/}};
+ }
+ if (cProps != nullptr) {
+ props = celix::Properties::wrap(cProps);
+ }
+ if (cBnd != nullptr) {
+ bnd = std::make_shared<celix::Bundle>(const_cast<celix_bundle_t*>(cBnd));
+ }
+
+ long prevSvcId = -1L;
+ std::shared_ptr<I> prevSvc{};
+ std::shared_ptr<const celix::Properties> prevProps{};
+ std::shared_ptr<const celix::Bundle> prevBnd{};
+ {
+ std::lock_guard<std::mutex> lck{tracker->mutex};
+ if (tracker->currentSetServiceId >= 0) {
+ prevSvcId = tracker->currentSetServiceId;
+ prevSvc = tracker->currentSetService;
+ prevProps = tracker->currentSetProperties;
+ prevBnd = tracker->currentSetBundle;
+ }
+ tracker->currentSetService = svc;
+ tracker->currentSetProperties = props;
+ tracker->currentSetBundle = bnd;
+ tracker->currentSetServiceId = props ? props->getAsLong(celix::SERVICE_ID, -1) : -1L;
+ }
+ for (const auto& func : tracker->setCallbacks) {
+ func(svc, props, bnd);
+ }
+ if (prevSvcId >= 0) {
+ tracker->waitForExpire(std::move(prevSvc), prevSvcId, "service");
+ tracker->waitForExpire(std::move(prevProps), prevSvcId, "celix::Properties");
+ tracker->waitForExpire(std::move(prevBnd), prevSvcId, "celix::Bundle");
+ }
+ };
+ }
+
+ ~ServiceTracker() override {
+ close(); //if state is OPEN, queue stop tracker.
+ wait(); //if state is CLOSING, wait till closing is complete.
+ }
+ private:
+ std::shared_ptr<I> getServiceForId(long id, void* voidSvc) {
+ std::lock_guard<std::mutex> lck{mutex};
+ auto it = services.find(id);
+ if (it == services.end()) {
+ //new
+ auto svc = std::shared_ptr<I>{static_cast<I*>(voidSvc), [](I*){/*nop*/}};
+ services[id] = svc;
+ return svc;
+ } else {
+ return it->second;
+ }
+ }
+
+ std::shared_ptr<const celix::Properties> getPropertiesForId(long id, const celix_properties_t * cProps) {
+ std::lock_guard<std::mutex> lck{mutex};
+ auto it = properties.find(id);
+ if (it == properties.end()) {
+ //new
+ auto props = celix::Properties::wrap(cProps);
+ properties[id] = props;
+ return props;
+ } else {
+ return it->second;
+ }
+ }
+
+ void waitForExpire(std::shared_ptr<const void> ptr, long observeSvcId, const char *objName) {
+ //observe.expired() not working
+ std::weak_ptr<const void> observe = ptr;
+ ptr = nullptr;
+ while (!observe.expired()) {
+ celix_bundleContext_log(cCtx.get(), CELIX_LOG_LEVEL_WARNING, "Cannot remove %s associated with service.id %li, because it is in use. Current shared_ptr use count is %i\n", objName, observeSvcId, (int)observe.use_count());
+ std::this_thread::sleep_for(std::chrono::seconds (1));
+ }
+ }
+
+ void removeAddRemEntriesForId(long svcId) {
+ std::lock_guard<std::mutex> lck{mutex};
+ services.erase(svcId);
+ properties.erase(svcId);
+ //bundles.erase(svcId);
+ }
+
+ const std::vector<std::function<void(std::shared_ptr<I>, std::shared_ptr<const celix::Properties>, std::shared_ptr<const celix::Bundle>)>> setCallbacks;
+ const std::vector<std::function<void(std::shared_ptr<I>, std::shared_ptr<const celix::Properties>, const celix::Bundle&)>> addCallbacks;
+ const std::vector<std::function<void(std::shared_ptr<I>, std::shared_ptr<const celix::Properties>, const celix::Bundle&)>> remCallbacks;
+
+ mutable std::mutex mutex{}; //protect below
+
+ std::unordered_map<long, std::shared_ptr<I>> services{};
+ std::unordered_map<long, std::shared_ptr<const celix::Properties>> properties{};
+ //std::unordered_map<long, std::shared_ptr<const celix::Bundle>> bundles{}; TODO
+
+ std::shared_ptr<I> currentSetService{};
+ std::shared_ptr<const celix::Properties> currentSetProperties{};
+ std::shared_ptr<const celix::Bundle> currentSetBundle{};
+ long currentSetServiceId{-1L};
+
+// std::unordered_map<SvcOrder, SvcEntry<I>{}; //TODO for update
+ };
+
+ /**
+ * \note Thread safe.
+ */
+ class BundleTracker : public AbstractTracker {
+ public:
+ BundleTracker(
+ std::shared_ptr<celix_bundle_context_t> _cCtx,
+ bool _includeFrameworkBundle,
+ std::vector<std::function<void(const celix::Bundle&)>> _onInstallCallbacks,
+ std::vector<std::function<void(const celix::Bundle&)>> _onStartCallbacks,
+ std::vector<std::function<void(const celix::Bundle&)>> _onStopCallbacks) :
+ AbstractTracker{std::move(_cCtx)},
+ includeFrameworkBundle{_includeFrameworkBundle},
+ onInstallCallbacks{std::move(_onInstallCallbacks)},
+ onStartCallbacks{std::move(_onStartCallbacks)},
+ onStopCallbacks{std::move(_onStopCallbacks)} {
+
+ opts.includeFrameworkBundle = includeFrameworkBundle;
+ 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)};
+ 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)};
+ 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)};
+ for (const auto& cb : tracker->onStopCallbacks) {
+ cb(bnd);
+ }
+ };
+ opts.trackerCreatedCallbackData = this;
+ opts.trackerCreatedCallback = [](void *data) {
+ auto* trk = static_cast<BundleTracker*>(data);
+ std::lock_guard<std::mutex> callbackLock{trk->mutex};
+ trk->state = TrackerState::OPEN;
+ };
+ }
+
+ ~BundleTracker() override {
+ close(); //if state is OPEN, queue stop tracker.
+ wait(); //if state is CLOSING, wait till closing is complete.
+ }
+
+ void open() override {
+ wait(); //if state is CLOSING, wait till tracker is closed
+ std::lock_guard<std::mutex> lck{mutex};
+ if (state == TrackerState::CLOSED) {
+ state = TrackerState::OPENING;
+
+ //NOTE the opts already configured the callbacks
+ trkId = celix_bundleContext_trackBundlesWithOptionsAsync(cCtx.get(), &opts);
+ }
+ }
+ private:
+ const bool includeFrameworkBundle;
+ const std::vector<std::function<void(const celix::Bundle&)>> onInstallCallbacks;
+ const std::vector<std::function<void(const celix::Bundle&)>> onStartCallbacks;
+ const std::vector<std::function<void(const celix::Bundle&)>> onStopCallbacks;
+ celix_bundle_tracking_options_t opts{}; //note only set in the ctor
+ };
+
+
+ /**
+ * A trivial struct containing information about a service tracker.
+ */
+ struct ServiceTrackerInfo {
+ /**
+ * The service name the service tracker is tracking.
+ * Will be '*' if the service tracker is tracking any services.
+ */
+ const std::string serviceName;
+
+ /**
+ * The service filter the service tracker is using for tracking.
+ */
+ const celix::Filter filter;
+
+ /**
+ * The bundle id of the owner of the service tracker.
+ */
+ const long trackerOwnerBundleId;
+ };
+
+ /**
+ * \note Thread safe.
+ */
+ class MetaTracker : public AbstractTracker {
+ public:
+ MetaTracker(
+ std::shared_ptr<celix_bundle_context_t> _cCtx,
+ std::string _serviceName,
+ std::vector<std::function<void(const ServiceTrackerInfo&)>> _onTrackerCreated,
+ std::vector<std::function<void(const ServiceTrackerInfo&)>> _onTrackerDestroyed) :
+ AbstractTracker{std::move(_cCtx)},
+ serviceName{std::move(_serviceName)},
+ onTrackerCreated{std::move(_onTrackerCreated)},
+ onTrackerDestroyed{std::move(_onTrackerDestroyed)} {}
+
+ ~MetaTracker() override {
+ close(); //if state is OPEN, queue stop tracker.
+ wait(); //if state is CLOSING, wait till closing is complete.
+ }
+
+ void open() override {
+ wait(); //if state is CLOSING, wait till tracker is closed
+ std::lock_guard<std::mutex> lck{mutex};
+ if (state == TrackerState::CLOSED) {
+ state = TrackerState::OPENING;
+
+ //NOTE the opts already configured the callbacks
+ trkId = celix_bundleContext_trackServiceTrackersAsync(
+ cCtx.get(),
+ serviceName.empty() ? nullptr : serviceName.c_str(),
+ static_cast<void*>(this),
+ [](void *handle, const celix_service_tracker_info_t *cInfo) {
+ auto *trk = static_cast<MetaTracker *>(handle);
+ ServiceTrackerInfo info{cInfo->serviceName, celix::Filter::wrap(cInfo->filter), cInfo->bundleId};
+ for (const auto& cb : trk->onTrackerCreated) {
+ cb(info);
+ }
+ },
+ [](void *handle, const celix_service_tracker_info_t *cInfo) {
+ auto *trk = static_cast<MetaTracker *>(handle);
+ ServiceTrackerInfo info{cInfo->serviceName, celix::Filter::wrap(cInfo->filter), cInfo->bundleId};
+ for (const auto& cb : trk->onTrackerDestroyed) {
+ cb(info);
+ }
+ },
+ static_cast<void*>(this),
+ [](void *data) {
+ auto *trk = static_cast<MetaTracker *>(data);
+ std::lock_guard<std::mutex> callbackLock{trk->mutex};
+ trk->state = TrackerState::OPEN;
+ });
+ }
+ }
+
+ private:
+ const std::string serviceName;
+ const std::vector<std::function<void(const ServiceTrackerInfo&)>> onTrackerCreated; //TODO check if the callback are done on started/stopped or created/destroyed
+ const std::vector<std::function<void(const ServiceTrackerInfo&)>> onTrackerDestroyed;
+ };
+
+}
\ No newline at end of file
diff --git a/libs/framework/include/celix/dm/types.h b/libs/framework/include/celix/Utils.h
similarity index 81%
copy from libs/framework/include/celix/dm/types.h
copy to libs/framework/include/celix/Utils.h
index 8ccf87f..58824e1 100644
--- a/libs/framework/include/celix/dm/types.h
+++ b/libs/framework/include/celix/Utils.h
@@ -19,35 +19,12 @@
#pragma once
-#include <map>
+
#include <string>
-#include <list>
-#include <tuple>
-#include <typeinfo>
-#include <memory>
-#include <cxxabi.h>
#include <string.h>
-#include "celix/dm/Properties.h"
-#include <stdlib.h>
#include <iostream>
-namespace celix { namespace dm {
- //forward declarations
- class DependencyManager;
-
- class BaseServiceDependency;
-
- class BaseProvidedService;
-
- template<typename T, typename I>
- class ProvidedService;
-
- template<class T, typename I>
- class CServiceDependency;
-
- template<class T, class I>
- class ServiceDependency;
-
+namespace celix {
/**
* Returns the deferred type name for the template I
*/
@@ -88,4 +65,12 @@ namespace celix { namespace dm {
return result;
}
-}}
+ /**
+ * Returns the deferred type name for the template I if hte providedTypeName is empty.
+ * Else returns the providedTypeName
+ */
+ template<typename I>
+ std::string typeName(const std::string& providedTypeName) {
+ return providedTypeName.empty() ? celix::typeName<I>() : providedTypeName;
+ }
+}
diff --git a/libs/framework/include/celix/dm/Component.h b/libs/framework/include/celix/dm/Component.h
index c5d9c59..4101aab 100644
--- a/libs/framework/include/celix/dm/Component.h
+++ b/libs/framework/include/celix/dm/Component.h
@@ -19,13 +19,23 @@
#pragma once
-#include "celix/dm/types.h"
-#include "dm_component.h"
-
#include <map>
#include <string>
#include <vector>
#include <atomic>
+#include <memory>
+#include <iostream>
+#include <type_traits>
+#include <algorithm>
+
+
+#include "dm_component.h"
+#include "celix/dm/types.h"
+#include "celix/dm/ServiceDependency.h"
+#include "celix/dm/ProvidedService.h"
+#include "celix_dependency_manager.h"
+
+
namespace celix { namespace dm {
diff --git a/libs/framework/include/celix/dm/Component_Impl.h b/libs/framework/include/celix/dm/Component_Impl.h
index 6e0d8f3..6b55ad8 100644
--- a/libs/framework/include/celix/dm/Component_Impl.h
+++ b/libs/framework/include/celix/dm/Component_Impl.h
@@ -17,19 +17,6 @@
* under the License.
*/
-#include "celix/dm/Component.h"
-#include "celix/dm/DependencyManager.h"
-#include "celix/dm/ServiceDependency.h"
-#include "celix/dm/ProvidedService.h"
-#include "celix_dependency_manager.h"
-
-#include <memory>
-#include <iostream>
-#include <iomanip>
-#include <type_traits>
-#include <algorithm>
-#include <atomic>
-
using namespace celix::dm;
inline void BaseComponent::runBuild() {
diff --git a/libs/framework/include/celix/dm/DependencyManager.h b/libs/framework/include/celix/dm/DependencyManager.h
index 6dc8a94..02cc472 100644
--- a/libs/framework/include/celix/dm/DependencyManager.h
+++ b/libs/framework/include/celix/dm/DependencyManager.h
@@ -21,7 +21,6 @@
#include "celix/dm/types.h"
#include "celix/dm/Component.h"
-#include "celix/dm/ServiceDependency.h"
#include "bundle_context.h"
#include "celix_bundle_context.h"
diff --git a/libs/framework/include/celix/dm/DependencyManager_Impl.h b/libs/framework/include/celix/dm/DependencyManager_Impl.h
index 3a05135..85a4fd4 100644
--- a/libs/framework/include/celix/dm/DependencyManager_Impl.h
+++ b/libs/framework/include/celix/dm/DependencyManager_Impl.h
@@ -17,7 +17,6 @@
* under the License.
*/
-#include "DependencyManager.h"
using namespace celix::dm;
diff --git a/libs/framework/include/celix/dm/Properties.h b/libs/framework/include/celix/dm/Properties.h
index 5c33885..e22d62d 100644
--- a/libs/framework/include/celix/dm/Properties.h
+++ b/libs/framework/include/celix/dm/Properties.h
@@ -19,9 +19,8 @@
#pragma once
-#include <map>
-#include <string>
+#include "celix/Properties.h"
namespace celix { namespace dm {
- using Properties = std::map<std::string, std::string>;
+ using Properties = celix::Properties;
}}
diff --git a/libs/framework/include/celix/dm/ProvidedService.h b/libs/framework/include/celix/dm/ProvidedService.h
index 76a4c2e..6723d37 100644
--- a/libs/framework/include/celix/dm/ProvidedService.h
+++ b/libs/framework/include/celix/dm/ProvidedService.h
@@ -22,7 +22,6 @@
#include <string>
#include <memory>
-#include "celix_api.h"
#include "celix/dm/Properties.h"
namespace celix { namespace dm {
diff --git a/libs/framework/include/celix/dm/ProvidedService_Impl.h b/libs/framework/include/celix/dm/ProvidedService_Impl.h
index 4cb9fbb..1035d18 100644
--- a/libs/framework/include/celix/dm/ProvidedService_Impl.h
+++ b/libs/framework/include/celix/dm/ProvidedService_Impl.h
@@ -43,8 +43,6 @@ inline void BaseProvidedService::runBuild() {
if (!provideAddedToCmp) {
//setup c properties
celix_properties_t *cProperties = properties_create();
- properties_set(cProperties, CELIX_FRAMEWORK_SERVICE_LANGUAGE,
- cppService ? CELIX_FRAMEWORK_SERVICE_CXX_LANGUAGE : CELIX_FRAMEWORK_SERVICE_C_LANGUAGE);
for (const auto &pair : properties) {
properties_set(cProperties, pair.first.c_str(), pair.second.c_str());
}
diff --git a/libs/framework/include/celix/dm/ServiceDependency.h b/libs/framework/include/celix/dm/ServiceDependency.h
index 0de57e9..bf057e6 100644
--- a/libs/framework/include/celix/dm/ServiceDependency.h
+++ b/libs/framework/include/celix/dm/ServiceDependency.h
@@ -19,9 +19,6 @@
#pragma once
-#include "dm_service_dependency.h"
-#include "celix/dm/types.h"
-
#include <map>
#include <string>
#include <list>
@@ -30,10 +27,16 @@
#include <iostream>
#include <functional>
#include <atomic>
+#include <vector>
+#include <cstring>
-namespace celix { namespace dm {
+#include "dm_service_dependency.h"
+#include "celix_constants.h"
+#include "celix_properties.h"
+#include "celix/Utils.h"
+#include "celix/dm/Properties.h"
- class DependencyManager; //forward declaration
+namespace celix { namespace dm {
enum class DependencyUpdateStrategy {
suspend,
@@ -338,11 +341,9 @@ namespace celix { namespace dm {
*/
ServiceDependency<T,I>& build();
private:
- bool addCxxLanguageFilter {true};
std::string name {};
std::string filter {};
std::string versionRange {};
- std::string modifiedFilter {};
std::function<void(I* service, Properties&& properties)> setFp{nullptr};
std::function<void(I* service, Properties&& properties)> addFp{nullptr};
diff --git a/libs/framework/include/celix/dm/ServiceDependency_Impl.h b/libs/framework/include/celix/dm/ServiceDependency_Impl.h
index a9dd5d2..70cb9ce 100644
--- a/libs/framework/include/celix/dm/ServiceDependency_Impl.h
+++ b/libs/framework/include/celix/dm/ServiceDependency_Impl.h
@@ -17,14 +17,6 @@
* under the License.
*/
-#include <vector>
-#include <iostream>
-#include <cstring>
-#include "celix_constants.h"
-#include "celix_properties.h"
-#include "ServiceDependency.h"
-
-
using namespace celix::dm;
inline void BaseServiceDependency::runBuild() {
@@ -253,7 +245,7 @@ void ServiceDependency<T,I>::setupService() {
std::string n = name;
if (n.empty()) {
- n = typeName<I>();
+ n = celix::typeName<I>();
if (n.empty()) {
std::cerr << "Error in service dependency. Type name cannot be inferred, using '<TYPE_NAME_ERROR>'. function: '" << __PRETTY_FUNCTION__ << "'\n";
n = "<TYPE_NAME_ERROR>";
@@ -261,40 +253,7 @@ void ServiceDependency<T,I>::setupService() {
}
const char* v = versionRange.empty() ? nullptr : versionRange.c_str();
-
-
- if (this->addCxxLanguageFilter) {
-
- char langFilter[128];
- snprintf(langFilter, sizeof(langFilter), "(%s=%s)", CELIX_FRAMEWORK_SERVICE_LANGUAGE,
- CELIX_FRAMEWORK_SERVICE_CXX_LANGUAGE);
-
- //setting modified filter. which is in a filter including a lang=c++
- modifiedFilter = std::string{langFilter};
- if (!filter.empty()) {
- char needle[128];
- snprintf(needle, sizeof(needle), "(%s=", CELIX_FRAMEWORK_SERVICE_LANGUAGE);
- size_t langFilterPos = filter.find(needle);
- if (langFilterPos != std::string::npos) {
- //do nothing filter already contains a language part.
- } else if (strncmp(filter.c_str(), "(&", 2) == 0 && filter[filter.size() - 1] == ')') {
- modifiedFilter = filter.substr(0, filter.size() - 1); //remove closing ')'
- modifiedFilter = modifiedFilter.append(langFilter);
- modifiedFilter = modifiedFilter.append(")"); //add closing ')'
- } else if (filter[0] == '(' && filter[filter.size() - 1] == ')') {
- modifiedFilter = "(&";
- modifiedFilter = modifiedFilter.append(filter);
- modifiedFilter = modifiedFilter.append(langFilter);
- modifiedFilter = modifiedFilter.append(")");
- } else {
- std::cerr << "Unexpected filter layout: '" << filter << "'\n";
- }
- }
- } else {
- this->modifiedFilter = this->filter;
- }
-
- celix_dmServiceDependency_setService(this->cServiceDependency(), n.c_str(), v, this->modifiedFilter.c_str());
+ celix_dmServiceDependency_setService(this->cServiceDependency(), n.c_str(), v, this->filter.c_str());
}
template<class T, class I>
diff --git a/libs/framework/include/celix/dm/types.h b/libs/framework/include/celix/dm/types.h
index 8ccf87f..a4a1944 100644
--- a/libs/framework/include/celix/dm/types.h
+++ b/libs/framework/include/celix/dm/types.h
@@ -27,13 +27,12 @@
#include <memory>
#include <cxxabi.h>
#include <string.h>
-#include "celix/dm/Properties.h"
#include <stdlib.h>
#include <iostream>
namespace celix { namespace dm {
//forward declarations
- class DependencyManager;
+// class DependencyManager;
class BaseServiceDependency;
@@ -48,44 +47,4 @@ namespace celix { namespace dm {
template<class T, class I>
class ServiceDependency;
- /**
- * Returns the deferred type name for the template I
- */
- template<typename INTERFACE_TYPENAME>
- std::string typeName() {
- std::string result;
-
-#ifdef __GXX_RTTI
- 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;
- }
-
}}
diff --git a/libs/framework/include/celix_api.h b/libs/framework/include/celix_api.h
index c66bae1..123f74a 100644
--- a/libs/framework/include/celix_api.h
+++ b/libs/framework/include/celix_api.h
@@ -46,8 +46,8 @@
#include "celix_framework_factory.h"
#ifdef __cplusplus
-#include "celix/dm/DependencyManager.h"
+#include "celix/BundleActivator.h"
+#include "celix/BundleContext.h"
#endif
-
#endif //CELIX_CELIX_API_H_
diff --git a/libs/framework/include/celix_bundle_activator.h b/libs/framework/include/celix_bundle_activator.h
index ab02ed2..aaaca2e 100644
--- a/libs/framework/include/celix_bundle_activator.h
+++ b/libs/framework/include/celix_bundle_activator.h
@@ -140,74 +140,6 @@ celix_status_t celix_bundleActivator_destroy(void *userData, celix_bundle_contex
#ifdef __cplusplus
}
-
-/**
- * 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:
- * - bundleActivator_create which allocates a pointer to the provided type.
- * - bundleActivator_start/stop which will call the respectively provided typed start/stop functions.
- * - bundleActivator_destroy will free the allocated for the provided type.
- *
- * @param type The activator type (e.g. 'ShellActivator'). A type which should have a constructor with a single arugment of std::shared_ptr<DependencyManager>.
- */
-#define CELIX_GEN_CXX_BUNDLE_ACTIVATOR(actType) \
- \
-namespace /*anon*/ { \
-struct BundleActivatorData { \
- std::shared_ptr<DependencyManager> mng{}; \
- std::unique_ptr<actType> activator{}; \
-}; \
-} \
- \
-extern "C" celix_status_t bundleActivator_create(celix_bundle_context_t *context, void** userData) { \
- int status = CELIX_SUCCESS; \
- \
- BundleActivatorData* data = nullptr; \
- data = new (std::nothrow) BundleActivatorData{}; \
- if (data != nullptr) { \
- data->mng = std::shared_ptr<celix::dm::DependencyManager>{new (std::nothrow) celix::dm::DependencyManager{context}}; \
- } \
- \
- if (data == nullptr || data->mng == nullptr) { \
- status = CELIX_ENOMEM; \
- if (data != nullptr) { \
- delete data; \
- } \
- *userData = nullptr; \
- } else { \
- *userData = data; \
- } \
- return status; \
-} \
- \
-extern "C" celix_status_t bundleActivator_start(void *userData, celix_bundle_context_t *) { \
- auto* data = static_cast<BundleActivatorData*>(userData); \
- if (data != nullptr) { \
- data->activator = std::unique_ptr<actType>{new actType{data->mng}}; \
- data->mng->start(); \
- } \
- return CELIX_SUCCESS; \
-} \
- \
-extern "C" celix_status_t bundleActivator_stop(void *userData, celix_bundle_context_t*) { \
- auto* data = static_cast<BundleActivatorData*>(userData); \
- if (data != nullptr) { \
- data->mng->stop(); \
- data->activator = nullptr; \
- data->mng = nullptr; \
- } \
- return CELIX_SUCCESS; \
-} \
- \
-extern "C" celix_status_t bundleActivator_destroy(void *userData, celix_bundle_context_t*) { \
- auto* data = static_cast<BundleActivatorData*>(userData); \
- delete data; \
- return CELIX_SUCCESS; \
-} \
-
-
#endif
#endif /* CELIX_BUNDLE_ACTIVATOR_H_ */
\ No newline at end of file
diff --git a/libs/framework/include/celix_bundle_context.h b/libs/framework/include/celix_bundle_context.h
index b99c8b5..d113f21 100644
--- a/libs/framework/include/celix_bundle_context.h
+++ b/libs/framework/include/celix_bundle_context.h
@@ -315,14 +315,15 @@ typedef struct celix_service_filter_options {
const char* filter OPTS_INIT;
/**
- * The optional service language to filter for. If this is NULL or "" the C language will be used.
+ * @deprecated This value is not used any more. If a service language filter is still required add it to the
+ * filter.
*/
const char* serviceLanguage OPTS_INIT;
/**
- * Whether to ignore (not filter for) the service.lang property.
- * If this is set the serviceLanguage field is ignored and the (service.lang=<>) part is not added tot he filter
+ * @deprecated This value is not used any more. If a service language filter is still required add it to the
+ * filter.
*/
bool ignoreServiceLanguage OPTS_INIT;
} celix_service_filter_options_t;
@@ -1055,7 +1056,8 @@ typedef struct celix_service_tracker_info {
const char *serviceName;
/**
- * The service language filter attribute parsed from the service filter. Can be null
+ * @deprecated
+ * Deprecated. the value will be NULL.
*/
const char *serviceLanguage;
@@ -1183,7 +1185,16 @@ double celix_bundleContext_getPropertyAsDouble(celix_bundle_context_t *ctx, cons
*/
bool celix_bundleContext_getPropertyAsBool(celix_bundle_context_t *ctx, const char *key, bool defaultValue);
-//TODO getPropertyAs for int, uint, ulong, bool, etc
+/**
+ * Logs a message to the Celix framework logger using the provided log level.
+ */
+void celix_bundleContext_log(celix_bundle_context_t *ctx, celix_log_level_e level, const char* format, ...);
+
+/**
+ * Logs a message to Celix framework logger using the provided log level.
+ */
+void celix_bundleContext_vlog(celix_bundle_context_t *ctx, celix_log_level_e level, const char *format, va_list formatArgs);
+
#undef OPTS_INIT
diff --git a/libs/framework/include/celix_constants.h b/libs/framework/include/celix_constants.h
index 17fb61f..4967fad 100644
--- a/libs/framework/include/celix_constants.h
+++ b/libs/framework/include/celix_constants.h
@@ -26,64 +26,62 @@
extern "C" {
#endif
-static const char *const OSGI_FRAMEWORK_OBJECTCLASS = "objectClass";
-static const char *const OSGI_FRAMEWORK_SERVICE_ID = "service.id";
-static const char *const OSGI_FRAMEWORK_SERVICE_PID = "service.pid";
+#define OSGI_FRAMEWORK_OBJECTCLASS "objectClass"
+#define OSGI_FRAMEWORK_SERVICE_ID "service.id"
+#define OSGI_FRAMEWORK_SERVICE_PID "service.pid"
/**
* Service property (named "service.ranking") identifying a service's ranking number (of type long).
* The default ranking is 0. A service with a ranking of LONG_MAX is very likely to be returned as the default service, whereas a service with a ranking of LONG_MIN is very unlikely to be returned.
* If the supplied property value cannot converted to long, a ranking value of 0 is used.
*/
-static const char *const OSGI_FRAMEWORK_SERVICE_RANKING = "service.ranking";
+#define OSGI_FRAMEWORK_SERVICE_RANKING "service.ranking"
-static const char *const CELIX_FRAMEWORK_SERVICE_VERSION = "service.version";
-static const char *const CELIX_FRAMEWORK_SERVICE_LANGUAGE = "service.lang";
-static const char *const CELIX_FRAMEWORK_SERVICE_C_LANGUAGE = "C";
-static const char *const CELIX_FRAMEWORK_SERVICE_CXX_LANGUAGE = "C++";
-static const char *const CELIX_FRAMEWORK_SERVICE_SHARED_LANGUAGE = "shared"; //e.g. marker services
+#define CELIX_FRAMEWORK_SERVICE_VERSION "service.version"
-static const char *const OSGI_FRAMEWORK_BUNDLE_ACTIVATOR = "Bundle-Activator";
-
-static const char *const OSGI_FRAMEWORK_BUNDLE_ACTIVATOR_CREATE = "celix_bundleActivator_create";
-static const char *const OSGI_FRAMEWORK_BUNDLE_ACTIVATOR_START = "celix_bundleActivator_start";
-static const char *const OSGI_FRAMEWORK_BUNDLE_ACTIVATOR_STOP = "celix_bundleActivator_stop";
-static const char *const OSGI_FRAMEWORK_BUNDLE_ACTIVATOR_DESTROY = "celix_bundleActivator_destroy";
-
-static const char *const OSGI_FRAMEWORK_DEPRECATED_BUNDLE_ACTIVATOR_CREATE = "bundleActivator_create";
-static const char *const OSGI_FRAMEWORK_DEPRECATED_BUNDLE_ACTIVATOR_START = "bundleActivator_start";
-static const char *const OSGI_FRAMEWORK_DEPRECATED_BUNDLE_ACTIVATOR_STOP = "bundleActivator_stop";
-static const char *const OSGI_FRAMEWORK_DEPRECATED_BUNDLE_ACTIVATOR_DESTROY = "bundleActivator_destroy";
+/**
+ * The service language property and values are deprecated
+ */
+//#define CELIX_FRAMEWORK_SERVICE_LANGUAGE "service.lang"
+//#define CELIX_FRAMEWORK_SERVICE_C_LANGUAGE "C"
+//#define CELIX_FRAMEWORK_SERVICE_CXX_LANGUAGE "C++"
+//#define CELIX_FRAMEWORK_SERVICE_SHARED_LANGUAGE "shared" //e.g. marker services
+#define OSGI_FRAMEWORK_BUNDLE_ACTIVATOR "Bundle-Activator"
-static const char *const OSGI_FRAMEWORK_BUNDLE_DM_ACTIVATOR_CREATE = "dm_create";
-static const char *const OSGI_FRAMEWORK_BUNDLE_DM_ACTIVATOR_INIT = "dm_init";
-static const char *const OSGI_FRAMEWORK_BUNDLE_DM_ACTIVATOR_DESTROY = "dm_destroy";
+#define OSGI_FRAMEWORK_BUNDLE_ACTIVATOR_CREATE "celix_bundleActivator_create"
+#define OSGI_FRAMEWORK_BUNDLE_ACTIVATOR_START "celix_bundleActivator_start"
+#define OSGI_FRAMEWORK_BUNDLE_ACTIVATOR_STOP "celix_bundleActivator_stop"
+#define OSGI_FRAMEWORK_BUNDLE_ACTIVATOR_DESTROY "celix_bundleActivator_destroy"
+#define OSGI_FRAMEWORK_DEPRECATED_BUNDLE_ACTIVATOR_CREATE "bundleActivator_create"
+#define OSGI_FRAMEWORK_DEPRECATED_BUNDLE_ACTIVATOR_START "bundleActivator_start"
+#define OSGI_FRAMEWORK_DEPRECATED_BUNDLE_ACTIVATOR_STOP "bundleActivator_stop"
+#define OSGI_FRAMEWORK_DEPRECATED_BUNDLE_ACTIVATOR_DESTROY "bundleActivator_destroy"
-static const char *const OSGI_FRAMEWORK_BUNDLE_SYMBOLICNAME = "Bundle-SymbolicName";
-static const char *const OSGI_FRAMEWORK_BUNDLE_VERSION = "Bundle-Version";
-static const char *const OSGI_FRAMEWORK_PRIVATE_LIBRARY = "Private-Library";
-static const char *const OSGI_FRAMEWORK_EXPORT_LIBRARY = "Export-Library";
-static const char *const OSGI_FRAMEWORK_IMPORT_LIBRARY = "Import-Library";
+#define OSGI_FRAMEWORK_BUNDLE_SYMBOLICNAME "Bundle-SymbolicName"
+#define OSGI_FRAMEWORK_BUNDLE_VERSION "Bundle-Version"
+#define OSGI_FRAMEWORK_PRIVATE_LIBRARY "Private-Library"
+#define OSGI_FRAMEWORK_EXPORT_LIBRARY "Export-Library"
+#define OSGI_FRAMEWORK_IMPORT_LIBRARY "Import-Library"
-static const char *const OSGI_FRAMEWORK_FRAMEWORK_STORAGE = "org.osgi.framework.storage";
-static const char *const OSGI_FRAMEWORK_STORAGE_USE_TMP_DIR = "org.osgi.framework.storage.use.tmp.dir";
-static const char *const OSGI_FRAMEWORK_FRAMEWORK_STORAGE_CLEAN_NAME = "org.osgi.framework.storage.clean";
-static const bool OSGI_FRAMEWORK_FRAMEWORK_STORAGE_CLEAN_DEFAULT = true;
-static const char *const OSGI_FRAMEWORK_FRAMEWORK_UUID = "org.osgi.framework.uuid";
+#define OSGI_FRAMEWORK_FRAMEWORK_STORAGE "org.osgi.framework.storage"
+#define OSGI_FRAMEWORK_STORAGE_USE_TMP_DIR "org.osgi.framework.storage.use.tmp.dir"
+#define OSGI_FRAMEWORK_FRAMEWORK_STORAGE_CLEAN_NAME "org.osgi.framework.storage.clean"
+#define OSGI_FRAMEWORK_FRAMEWORK_STORAGE_CLEAN_DEFAULT true
+#define OSGI_FRAMEWORK_FRAMEWORK_UUID "org.osgi.framework.uuid"
-static const char *const CELIX_BUNDLES_PATH_NAME = "CELIX_BUNDLES_PATH";
-static const char *const CELIX_BUNDLES_PATH_DEFAULT = "bundles";
+#define CELIX_BUNDLES_PATH_NAME "CELIX_BUNDLES_PATH"
+#define CELIX_BUNDLES_PATH_DEFAULT "bundles"
-static const char *const CELIX_LOAD_BUNDLES_WITH_NODELETE = "CELIX_LOAD_BUNDLES_WITH_NODELETE";
+#define CELIX_LOAD_BUNDLES_WITH_NODELETE "CELIX_LOAD_BUNDLES_WITH_NODELETE"
/**
* The path used getting entries from the framework bundle.
* Normal bundles have an archive directory.
* For the celix framework by default the working directory is used, with this configuration this can be changed.
*/
-static const char *const CELIX_SYSTEM_BUNDLE_ARCHIVE_PATH = "CELIX_SYSTEM_BUNDLE_ARCHIVE_PATH";
+#define CELIX_SYSTEM_BUNDLE_ARCHIVE_PATH "CELIX_SYSTEM_BUNDLE_ARCHIVE_PATH"
#define CELIX_AUTO_START_0 "CELIX_AUTO_START_0"
diff --git a/libs/framework/include/celix_log.h b/libs/framework/include/celix_log.h
index 2a56695..c170342 100644
--- a/libs/framework/include/celix_log.h
+++ b/libs/framework/include/celix_log.h
@@ -64,6 +64,8 @@ void framework_log(celix_framework_logger_t* logger, celix_log_level_e level, co
void framework_logCode(celix_framework_logger_t* logger, celix_log_level_e level, const char *func, const char *file, int line,
celix_status_t code, const char *format, ...);
+void celix_framework_vlog(celix_framework_logger_t* logger, celix_log_level_e level, celix_status_t *optionalStatus, const char* file, const char* function, int line, const char* format, va_list args);
+
#ifdef __cplusplus
}
#endif
diff --git a/libs/framework/include/dm_component.h b/libs/framework/include/dm_component.h
index 84cb3d7..92b5b93 100644
--- a/libs/framework/include/dm_component.h
+++ b/libs/framework/include/dm_component.h
@@ -63,8 +63,7 @@ void component_destroy(celix_dm_component_t *component) CELIX_DEPRECATED_ATTR;
/**
- * Specify if a default 'service.lang=C' should be added to the properties of interfaces if no 'service.lang' has been
- * provided. Default is false. Note that this should be set before using component_addInterface.
+ * @deprecated Deprecated. not used ny mowre
*/
celix_status_t component_setCLanguageProperty(celix_dm_component_t *component, bool setCLangProp) CELIX_DEPRECATED_ATTR;
diff --git a/libs/framework/include/service_registry.h b/libs/framework/include/service_registry.h
index 275f707..87cd6c9 100644
--- a/libs/framework/include/service_registry.h
+++ b/libs/framework/include/service_registry.h
@@ -164,9 +164,7 @@ char* celix_serviceRegistry_createFilterFor(
celix_service_registry_t* registry,
const char* serviceName,
const char* versionRange,
- const char* additionalFilter,
- const char* serviceLanguage,
- bool ignoreServiceLanguage);
+ const char* additionalFilter);
/**
* Find services and return a array list of service ids (long).
diff --git a/libs/framework/src/bundle_context.c b/libs/framework/src/bundle_context.c
index 2f1473d..819c8df 100644
--- a/libs/framework/src/bundle_context.c
+++ b/libs/framework/src/bundle_context.c
@@ -23,6 +23,7 @@
#include <utils.h>
#include <assert.h>
#include <unistd.h>
+#include <stdarg.h>
#include "celix_utils.h"
#include "celix_constants.h"
@@ -501,8 +502,6 @@ static long celix_bundleContext_registerServiceWithOptionsInternal(bundle_contex
if (opts->serviceVersion != NULL && strncmp("", opts->serviceVersion, 1) != 0) {
celix_properties_set(props, CELIX_FRAMEWORK_SERVICE_VERSION, opts->serviceVersion);
}
- const char *lang = opts->serviceLanguage != NULL && strncmp("", opts->serviceLanguage, 1) != 0 ? opts->serviceLanguage : CELIX_FRAMEWORK_SERVICE_C_LANGUAGE;
- celix_properties_set(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang);
long svcId = -1;
if (!async && celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) {
@@ -1425,7 +1424,7 @@ long celix_bundleContext_findService(celix_bundle_context_t *ctx, const char *se
long celix_bundleContext_findServiceWithOptions(celix_bundle_context_t *ctx, const celix_service_filter_options_t *opts) {
long result = -1L;
- char* filter = celix_serviceRegistry_createFilterFor(ctx->framework->registry, opts->serviceName, opts->versionRange, opts->filter, opts->serviceLanguage, opts->ignoreServiceLanguage);
+ char* filter = celix_serviceRegistry_createFilterFor(ctx->framework->registry, opts->serviceName, opts->versionRange, opts->filter);
if (filter != NULL) {
celix_array_list_t *svcIds = celix_serviceRegisrty_findServices(ctx->framework->registry, filter);
if (svcIds != NULL && celix_arrayList_size(svcIds) > 0) {
@@ -1448,7 +1447,7 @@ celix_array_list_t* celix_bundleContext_findServices(celix_bundle_context_t *ctx
celix_array_list_t* celix_bundleContext_findServicesWithOptions(celix_bundle_context_t *ctx, const celix_service_filter_options_t *opts) {
celix_array_list_t* result = NULL;
- char* filter = celix_serviceRegistry_createFilterFor(ctx->framework->registry, opts->serviceName, opts->versionRange, opts->filter, opts->serviceLanguage, opts->ignoreServiceLanguage);
+ char* filter = celix_serviceRegistry_createFilterFor(ctx->framework->registry, opts->serviceName, opts->versionRange, opts->filter);
if (filter != NULL) {
result = celix_serviceRegisrty_findServices(ctx->framework->registry, filter);
free(filter);
@@ -1470,7 +1469,6 @@ static celix_status_t bundleContext_callServicedTrackerTrackerCallback(void *han
trkInfo.bundleId = celix_bundle_getId(bnd);
trkInfo.filter = celix_filter_create(info->filter);
trkInfo.serviceName = celix_filter_findAttribute(trkInfo.filter, OSGI_FRAMEWORK_OBJECTCLASS);
- trkInfo.serviceLanguage = celix_filter_findAttribute(trkInfo.filter, CELIX_FRAMEWORK_SERVICE_LANGUAGE);
const char *filterSvcName = celix_filter_findAttribute(trkInfo.filter, OSGI_FRAMEWORK_OBJECTCLASS);
bool match = entry->serviceName == NULL || (filterSvcName != NULL && strncmp(filterSvcName, entry->serviceName, 1024*1024) == 0);
@@ -1649,3 +1647,14 @@ char* celix_bundleContext_getBundleSymbolicName(celix_bundle_context_t *ctx, lon
celix_framework_useBundle(ctx->framework, false, bndId, &name, celix_bundleContext_getBundleSymbolicNameCallback);
return name;
}
+
+void celix_bundleContext_log(celix_bundle_context_t *ctx, celix_log_level_e level, const char* format, ...) {
+ va_list args;
+ va_start(args, format);
+ celix_bundleContext_vlog(ctx, level, format, args);
+ va_end(args);
+}
+
+void celix_bundleContext_vlog(celix_bundle_context_t *ctx, celix_log_level_e level, const char *format, va_list formatArgs) {
+ celix_framework_vlog(ctx->framework->logger, level, NULL, NULL, NULL, 0, format, formatArgs);
+}
\ No newline at end of file
diff --git a/libs/framework/src/celix_log.c b/libs/framework/src/celix_log.c
index 012283d..e959d35 100644
--- a/libs/framework/src/celix_log.c
+++ b/libs/framework/src/celix_log.c
@@ -103,7 +103,7 @@ void celix_frameworkLogger_setLogCallback(celix_framework_logger_t* logger, void
}
-static void vlog(celix_framework_logger_t* logger, celix_log_level_e level, celix_status_t *optionalStatus, const char* file, const char* function, int line, const char* format, va_list args) {
+void celix_framework_vlog(celix_framework_logger_t* logger, celix_log_level_e level, celix_status_t *optionalStatus, const char* file, const char* function, int line, const char* format, va_list args) {
if (level == CELIX_LOG_LEVEL_DISABLED) {
return;
}
@@ -130,13 +130,13 @@ static void vlog(celix_framework_logger_t* logger, celix_log_level_e level, celi
void framework_log(celix_framework_logger_t* logger, celix_log_level_e level, const char *func, const char *file, int line, const char *format, ...) {
va_list args;
va_start(args, format);
- vlog(logger, level, NULL, file, func, line, format, args);
+ celix_framework_vlog(logger, level, NULL, file, func, line, format, args);
va_end(args);
}
void framework_logCode(celix_framework_logger_t* logger, celix_log_level_e level, const char *func, const char *file, int line, celix_status_t code, const char *format, ...) {
va_list args;
va_start(args, format);
- vlog(logger, level, &code, file, func, line, format, args);
+ celix_framework_vlog(logger, level, &code, file, func, line, format, args);
va_end(args);
}
\ No newline at end of file
diff --git a/libs/framework/src/dm_component_impl.c b/libs/framework/src/dm_component_impl.c
index b76f8e9..5077b2b 100644
--- a/libs/framework/src/dm_component_impl.c
+++ b/libs/framework/src/dm_component_impl.c
@@ -50,8 +50,6 @@ struct celix_dm_component_struct {
bool isStarted;
bool active;
- bool setCLanguageProperty;
-
hash_map_pt dependencyEvents; //protected by mutex
dm_executor_pt executor;
@@ -152,8 +150,6 @@ celix_dm_component_t* celix_dmComponent_create(bundle_context_t *context, const
component->isStarted = false;
component->active = false;
- component->setCLanguageProperty = false;
-
component->dependencyEvents = hashMap_create(NULL, NULL, NULL, NULL);
component->executor = NULL;
@@ -360,7 +356,7 @@ celix_status_t component_setCLanguageProperty(celix_dm_component_t *component, b
}
celix_status_t celix_dmComponent_setCLanguageProperty(celix_dm_component_t *component, bool setCLangProp) {
- component->setCLanguageProperty = setCLangProp;
+ //nop
return CELIX_SUCCESS;
}
@@ -382,10 +378,6 @@ celix_status_t celix_dmComponent_addInterface(celix_dm_component_t *component, c
celix_properties_set(properties, CELIX_FRAMEWORK_SERVICE_VERSION, serviceVersion);
}
- if (component->setCLanguageProperty && properties_get(properties, CELIX_FRAMEWORK_SERVICE_LANGUAGE) == NULL) { //always set default lang to C
- celix_properties_set(properties, CELIX_FRAMEWORK_SERVICE_LANGUAGE, CELIX_FRAMEWORK_SERVICE_C_LANGUAGE);
- }
-
celix_properties_set(properties, CELIX_DM_COMPONENT_UUID, (char*)component->id);
if (interface && name) {
@@ -1256,7 +1248,6 @@ static celix_status_t component_registerServices(celix_dm_component_t *component
opts.properties = regProps;
opts.svc = (void*)interface->service;
opts.serviceName = interface->serviceName;
- opts.serviceLanguage = celix_properties_get(regProps, CELIX_FRAMEWORK_SERVICE_LANGUAGE, NULL);
interface->svcId = celix_bundleContext_registerServiceWithOptions(component->context, &opts);
}
}
diff --git a/libs/framework/src/dm_service_dependency.c b/libs/framework/src/dm_service_dependency.c
index 52118d2..b98760d 100644
--- a/libs/framework/src/dm_service_dependency.c
+++ b/libs/framework/src/dm_service_dependency.c
@@ -214,23 +214,6 @@ celix_status_t celix_dmServiceDependency_setService(celix_dm_service_dependency_
arrayList_add(filterElements, strdup(filter));
}
-
-
- bool needLangFilter = true;
- if (filter != NULL) {
- char needle[128];
- snprintf(needle, sizeof(needle), "(%s=", CELIX_FRAMEWORK_SERVICE_LANGUAGE);
- if (strstr(filter, needle) != NULL) {
- needLangFilter = false;
- }
- }
-
- if (needLangFilter && dependency->addCLanguageFilter) {
- char langFilter[128];
- snprintf(langFilter, sizeof(langFilter), "(%s=%s)", CELIX_FRAMEWORK_SERVICE_LANGUAGE, CELIX_FRAMEWORK_SERVICE_C_LANGUAGE);
- arrayList_add(filterElements, strdup(langFilter));
- }
-
if (arrayList_size(filterElements) > 0) {
array_list_iterator_pt filterElementsIter = arrayListIterator_create(filterElements);
diff --git a/libs/framework/src/service_registry.c b/libs/framework/src/service_registry.c
index 1b2924c..5953980 100644
--- a/libs/framework/src/service_registry.c
+++ b/libs/framework/src/service_registry.c
@@ -921,14 +921,9 @@ static inline void celix_waitAndDestroyServiceListener(celix_service_registry_se
free(entry);
}
-char* celix_serviceRegistry_createFilterFor(celix_service_registry_t* registry, const char* serviceName, const char* versionRangeStr, const char* additionalFilterIn, const char* lang, bool ignoreServiceLanguage) {
+char* celix_serviceRegistry_createFilterFor(celix_service_registry_t* registry, const char* serviceName, const char* versionRangeStr, const char* additionalFilterIn) {
char* filter = NULL;
- //setting lang
- if (lang == NULL || strncmp("", lang, 1) == 0) {
- lang = CELIX_FRAMEWORK_SERVICE_C_LANGUAGE;
- }
-
if (serviceName == NULL) {
serviceName = "*";
}
@@ -952,26 +947,14 @@ char* celix_serviceRegistry_createFilterFor(celix_service_registry_t* registry,
}
//setting filter
- if (ignoreServiceLanguage) {
- if (additionalFilterIn != NULL && versionRange != NULL) {
- asprintf(&filter, "(&(%s=%s)%s%s)", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, versionRange, additionalFilterIn);
- } else if (versionRange != NULL) {
- asprintf(&filter, "(&(%s=%s)%s)", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, versionRange);
- } else if (additionalFilterIn != NULL) {
- asprintf(&filter, "(&(%s=%s)%s)", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, additionalFilterIn);
- } else {
- asprintf(&filter, "(&(%s=%s))", OSGI_FRAMEWORK_OBJECTCLASS, serviceName);
- }
+ if (additionalFilterIn != NULL && versionRange != NULL) {
+ asprintf(&filter, "(&(%s=%s)%s%s)", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, versionRange, additionalFilterIn);
+ } else if (versionRange != NULL) {
+ asprintf(&filter, "(&(%s=%s)%s)", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, versionRange);
+ } else if (additionalFilterIn != NULL) {
+ asprintf(&filter, "(&(%s=%s)%s)", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, additionalFilterIn);
} else {
- if (additionalFilterIn != NULL && versionRange != NULL) {
- asprintf(&filter, "(&(%s=%s)(%s=%s)%s%s)", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang, versionRange, additionalFilterIn);
- } else if (versionRange != NULL) {
- asprintf(&filter, "(&(%s=%s)(%s=%s)%s)", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang, versionRange);
- } else if (additionalFilterIn != NULL) {
- asprintf(&filter, "(&(%s=%s)(%s=%s)%s)", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang, additionalFilterIn);
- } else {
- asprintf(&filter, "(&(%s=%s)(%s=%s))", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang);
- }
+ asprintf(&filter, "(&(%s=%s))", OSGI_FRAMEWORK_OBJECTCLASS, serviceName);
}
if (versionRange != NULL){
diff --git a/libs/framework/src/service_tracker.c b/libs/framework/src/service_tracker.c
index 4a47397..f28d503 100644
--- a/libs/framework/src/service_tracker.c
+++ b/libs/framework/src/service_tracker.c
@@ -658,7 +658,7 @@ celix_service_tracker_t* celix_serviceTracker_createWithOptions(
tracker->listener.handle = tracker;
tracker->listener.serviceChanged = (void *) serviceTracker_serviceChanged;
- tracker->filter = celix_serviceRegistry_createFilterFor(ctx->framework->registry, opts->filter.serviceName, opts->filter.versionRange, opts->filter.filter, opts->filter.serviceLanguage, opts->filter.ignoreServiceLanguage);
+ tracker->filter = celix_serviceRegistry_createFilterFor(ctx->framework->registry, opts->filter.serviceName, opts->filter.versionRange, opts->filter.filter);
if (tracker->filter == NULL) {
framework_log(tracker->context->framework->logger, CELIX_LOG_LEVEL_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__,
diff --git a/libs/utils/src/filter.c b/libs/utils/src/filter.c
index c07b54e..615d1fb 100644
--- a/libs/utils/src/filter.c
+++ b/libs/utils/src/filter.c
@@ -714,7 +714,7 @@ const char* celix_filter_findAttribute(const celix_filter_t *filter, const char
}
}
} else if (strncmp(filter->attribute, attribute, 1024 * 1024) == 0) {
- result = filter->value;
+ result = filter->operand == CELIX_FILTER_OPERAND_PRESENT ? "*" : filter->value;
}
}
return result;
diff --git a/libs/utils/src/properties.c b/libs/utils/src/properties.c
index caf0769..c735a76 100644
--- a/libs/utils/src/properties.c
+++ b/libs/utils/src/properties.c
@@ -346,7 +346,7 @@ void celix_properties_store(celix_properties_t *properties, const char *filename
celix_properties_t* celix_properties_copy(const celix_properties_t *properties) {
celix_properties_t *copy = celix_properties_create();
- if (copy != NULL) {
+ if (properties != NULL) {
hash_map_iterator_t iter = hashMapIterator_construct((hash_map_t*)properties);
while (hashMapIterator_hasNext(&iter)) {
hash_map_entry_pt entry = hashMapIterator_nextEntry(&iter);