This is an automated email from the ASF dual-hosted git repository. pnoltes pushed a commit to branch feature/cxx_rsa_update in repository https://gitbox.apache.org/repos/asf/celix.git
commit 883baadcc6492e6f3d76e46904be1a8351def356 Author: Pepijn Noltes <[email protected]> AuthorDate: Thu Apr 15 19:31:05 2021 +0200 Refactors C++ remote service admin to use IExport(Import)ServiceFactory SPI. --- bundles/async_remote_services/CMakeLists.txt | 12 +- bundles/async_remote_services/admin/CMakeLists.txt | 32 ++- .../{ => admin/gtest}/CMakeLists.txt | 22 +- .../admin/gtest/src/RemoteServiceAdminTestSuite.cc | 279 +++++++++++++++++++++ .../async_remote_services/admin/include/admin.h | 61 ++--- bundles/async_remote_services/admin/src/admin.cc | 166 ++++++------ .../async_remote_services/common/CMakeLists.txt | 1 + .../common/include/ImportedServiceFactory.h | 1 - .../async_remote_services/examples/CMakeLists.txt | 8 +- .../async_remote_services/rsa_spi/CMakeLists.txt | 1 - .../rsa_spi/include/celix/rsa/Constants.h | 10 +- .../rsa_spi/include/celix/rsa/Endpoint.h | 12 +- .../include/celix/rsa/IExportServiceFactory.h | 22 +- .../include/celix/rsa/IImportServiceFactory.h | 22 +- libs/framework/include/celix/ServiceRegistration.h | 8 +- .../include/celix/dm/DependencyManager_Impl.h | 2 +- 16 files changed, 453 insertions(+), 206 deletions(-) diff --git a/bundles/async_remote_services/CMakeLists.txt b/bundles/async_remote_services/CMakeLists.txt index c71b538..2257092 100644 --- a/bundles/async_remote_services/CMakeLists.txt +++ b/bundles/async_remote_services/CMakeLists.txt @@ -15,12 +15,12 @@ # specific language governing permissions and limitations # under the License. -celix_subproject(ASYNC_REMOTE_SERVICE_ADMIN "Option to enable building the C++17 async Remote Service Admin Service bundles" OFF) -if (ASYNC_REMOTE_SERVICE_ADMIN) - add_subdirectory(common) +celix_subproject(REMOTE_SERVICE_ADMIN "Option to enable building the C++17 Remote Service Admin Service bundles" OFF) +if (REMOTE_SERVICE_ADMIN) + #add_subdirectory(common) add_subdirectory(rsa_spi) add_subdirectory(admin) - add_subdirectory(topology_manager) - add_subdirectory(discovery_configured) - add_subdirectory(examples) + #add_subdirectory(topology_manager) + #add_subdirectory(discovery_configured) + #add_subdirectory(examples) endif() \ No newline at end of file diff --git a/bundles/async_remote_services/admin/CMakeLists.txt b/bundles/async_remote_services/admin/CMakeLists.txt index b74c41e..4eee9c1 100644 --- a/bundles/async_remote_services/admin/CMakeLists.txt +++ b/bundles/async_remote_services/admin/CMakeLists.txt @@ -15,29 +15,27 @@ # specific language governing permissions and limitations # under the License. -add_celix_bundle(async_rsa +add_celix_bundle(RemoteServiceAdmin VERSION 0.9.0 - SYMBOLIC_NAME "apache_celix_async_remote_service_admin" - NAME "Apache Celix Async Remote Service Admin" - GROUP "Celix/AsyncRSA" + SYMBOLIC_NAME "celix::RemoteServiceAdmin" + NAME "Apache Celix Remote Service Admin" + GROUP "Celix/RSA" + FILENAME "Celix_RemoteServiceAdmin" SOURCES - src/admin.cc - ) -target_include_directories(async_rsa PRIVATE include) -target_link_libraries(async_rsa PRIVATE - Celix::async_rsa_common - Celix::pubsub_api - Celix::pubsub_spi + src/admin.cc +) +target_include_directories(RemoteServiceAdmin PRIVATE include) +target_link_libraries(RemoteServiceAdmin PRIVATE Celix::rsa_spi Celix::framework Celix::log_helper - ) +) -#if (ENABLE_TESTING) -# add_subdirectory(gtest) -#endif() +if (ENABLE_TESTING) + add_subdirectory(gtest) +endif() -install_celix_bundle(async_rsa EXPORT celix COMPONENT async_rsa) +install_celix_bundle(RemoteServiceAdmin EXPORT celix COMPONENT rsa) #Setup target aliases to match external usage -add_library(Celix::async_rsa ALIAS async_rsa) \ No newline at end of file +add_library(Celix::RemoteServiceAdmin ALIAS RemoteServiceAdmin) \ No newline at end of file diff --git a/bundles/async_remote_services/CMakeLists.txt b/bundles/async_remote_services/admin/gtest/CMakeLists.txt similarity index 54% copy from bundles/async_remote_services/CMakeLists.txt copy to bundles/async_remote_services/admin/gtest/CMakeLists.txt index c71b538..42e2ce8 100644 --- a/bundles/async_remote_services/CMakeLists.txt +++ b/bundles/async_remote_services/admin/gtest/CMakeLists.txt @@ -15,12 +15,16 @@ # specific language governing permissions and limitations # under the License. -celix_subproject(ASYNC_REMOTE_SERVICE_ADMIN "Option to enable building the C++17 async Remote Service Admin Service bundles" OFF) -if (ASYNC_REMOTE_SERVICE_ADMIN) - add_subdirectory(common) - add_subdirectory(rsa_spi) - add_subdirectory(admin) - add_subdirectory(topology_manager) - add_subdirectory(discovery_configured) - add_subdirectory(examples) -endif() \ No newline at end of file +add_executable(test_cxx_remote_service_admin + src/RemoteServiceAdminTestSuite.cc +) + +target_link_libraries(test_cxx_remote_service_admin PRIVATE Celix::framework GTest::gtest GTest::gtest_main Celix::rsa_spi) +add_dependencies(test_cxx_remote_service_admin RemoteServiceAdmin_bundle) + +celix_get_bundle_file(RemoteServiceAdmin REMOTE_SERVICE_ADMIN_BUNDLE_LOCATION) +target_compile_definitions(test_cxx_remote_service_admin PRIVATE REMOTE_SERVICE_ADMIN_BUNDLE_LOCATION="${REMOTE_SERVICE_ADMIN_BUNDLE_LOCATION}") + + +add_test(NAME test_cxx_remote_service_admin COMMAND test_cxx_remote_service_admin) +setup_target_for_coverage(test_cxx_remote_service_admin SCAN_DIR ..) \ No newline at end of file diff --git a/bundles/async_remote_services/admin/gtest/src/RemoteServiceAdminTestSuite.cc b/bundles/async_remote_services/admin/gtest/src/RemoteServiceAdminTestSuite.cc new file mode 100644 index 0000000..20ff87e --- /dev/null +++ b/bundles/async_remote_services/admin/gtest/src/RemoteServiceAdminTestSuite.cc @@ -0,0 +1,279 @@ +/* + * 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/FrameworkFactory.h" +#include "celix/rsa/IExportServiceFactory.h" +#include "celix/rsa/IExportedService.h" +#include "celix/rsa/IImportServiceFactory.h" +#include "celix/rsa/Constants.h" + +class RemoteServiceAdminTestSuite : public ::testing::Test { +public: + RemoteServiceAdminTestSuite() { + fw = celix::createFramework(); + ctx = fw->getFrameworkBundleContext(); + } + + std::shared_ptr<celix::Framework> fw{}; + std::shared_ptr<celix::BundleContext> ctx{}; +}; + +TEST_F(RemoteServiceAdminTestSuite, startStopStartStopBundle) { + auto bndId = ctx->installBundle(REMOTE_SERVICE_ADMIN_BUNDLE_LOCATION); + EXPECT_GE(bndId, 0); + ctx->stopBundle(bndId); + ctx->startBundle(bndId); +} + + +/** + * The StubExported* classes mimic the expected behaviour of export service factories so that this can be used to test + * the RemoteServiceAdmin. + */ + +class StubExportedService : public celix::rsa::IExportedService { +public: + ~StubExportedService() noexcept override = default; + std::shared_ptr<celix::rsa::Endpoint> getEndpoint() override { + return endpoint; + } +private: + std::shared_ptr<celix::rsa::Endpoint> endpoint = std::make_shared<celix::rsa::Endpoint>(celix::Properties{}); //can be empty for stub +}; + +class StubExportedServiceGuard { +public: + explicit StubExportedServiceGuard(std::shared_ptr<celix::ServiceRegistration> _reg) : reg{std::move(_reg)} {} + + void close() { + reg->unregister(); + } +private: + const std::shared_ptr<celix::ServiceRegistration> reg; +}; + +class StubExportServiceRegistration : public celix::rsa::IExportServiceRegistration { +public: + explicit StubExportServiceRegistration(std::weak_ptr<StubExportedServiceGuard> _guard) : guard{std::move(_guard)} {} + ~StubExportServiceRegistration() noexcept override { + auto g = guard.lock(); + if (g) { + g->close(); + } + } + +private: + const std::weak_ptr<StubExportedServiceGuard> guard; +}; + +class StubExportServiceFactory : public celix::rsa::IExportServiceFactory { +public: + explicit StubExportServiceFactory(std::shared_ptr<celix::BundleContext> _ctx) : ctx{std::move(_ctx)} {} + + std::unique_ptr<celix::rsa::IExportServiceRegistration> exportService(const celix::Properties& /*serviceProperties*/) override { + auto svcReg= ctx->registerService<celix::rsa::IExportedService>(std::make_shared<StubExportedService>()).build(); + auto guard = std::make_shared<StubExportedServiceGuard>(std::move(svcReg)); + + std::lock_guard<std::mutex> lock{mutex}; + guards.emplace_back(guard); + return std::make_unique<StubExportServiceRegistration>(guard); + } + +private: + const std::shared_ptr<celix::BundleContext> ctx; + std::mutex mutex{}; + std::vector<std::shared_ptr<StubExportedServiceGuard>> guards{}; +}; + +class IDummyService { +public: + virtual ~IDummyService() noexcept = default; +}; + +class DummyServiceImpl : public IDummyService { +public: + ~DummyServiceImpl() noexcept override = default; +}; + +TEST_F(RemoteServiceAdminTestSuite, exportService) { + auto bndId = ctx->installBundle(REMOTE_SERVICE_ADMIN_BUNDLE_LOCATION); + EXPECT_GE(bndId, 0); + + /** + * When I add a export service factory and register a service with exported interfaces the + * RemoteServiceAdmin will create a ExportedService with using the service factory + */ + auto count = ctx->useService<celix::rsa::IExportedService>() + .build(); + EXPECT_EQ(0, count); + + auto reg1 = ctx->registerService<celix::rsa::IExportServiceFactory>(std::make_shared<StubExportServiceFactory>(ctx)) + .addProperty(celix::rsa::IExportServiceFactory::TARGET_SERVICE_NAME, celix::typeName<IDummyService>()) + .build(); + + count = ctx->useService<celix::rsa::IExportedService>() + .build(); + EXPECT_EQ(0, count); + + auto reg2 = ctx->registerService<IDummyService>(std::make_shared<DummyServiceImpl>()) + .addProperty(celix::rsa::REMOTE_SERVICE_EXPORTED_PROPERTY_NAME, true) + .build(); + + //rsa called export service factory which created a IExportServiceRegistration, which register the marker interface IExportedService indicating an exported service + count = ctx->useService<celix::rsa::IExportedService>() + .build(); + EXPECT_EQ(1, count); + + + reg1->unregister(); + + //removed factory -> removed exported interface + count = ctx->useService<celix::rsa::IExportedService>() + .build(); + EXPECT_EQ(0, count); +} + +TEST_F(RemoteServiceAdminTestSuite, exportServiceDifferentOrder) { + auto bndId = ctx->installBundle(REMOTE_SERVICE_ADMIN_BUNDLE_LOCATION); + EXPECT_GE(bndId, 0); + + /** + * When I add a export service factory and register a service with exported interfaces the + * RemoteServiceAdmin will create a ExportedService with using the service factory + */ + auto count = ctx->useService<celix::rsa::IExportedService>() + .build(); + EXPECT_EQ(0, count); + + auto reg1 = ctx->registerService<IDummyService>(std::make_shared<DummyServiceImpl>()) + .addProperty(celix::rsa::REMOTE_SERVICE_EXPORTED_PROPERTY_NAME, true) + .build(); + + count = ctx->useService<celix::rsa::IExportedService>() + .build(); + EXPECT_EQ(0, count); + + auto reg2 = ctx->registerService<celix::rsa::IExportServiceFactory>(std::make_shared<StubExportServiceFactory>(ctx)) + .addProperty(celix::rsa::IExportServiceFactory::TARGET_SERVICE_NAME, celix::typeName<IDummyService>()) + .build(); + + //rsa called export service factory which created a IExportServiceRegistration, which register the marker interface IExportedService indicating an exported service + count = ctx->useService<celix::rsa::IExportedService>() + .build(); + EXPECT_EQ(1, count); +} + + + + +/** + * The StubImported* classes mimic the expected behaviour of import service factories so that this can be used to test + * the RemoteServiceAdmin. + */ + +class StubImportedServiceGuard { +public: + explicit StubImportedServiceGuard(std::shared_ptr<celix::ServiceRegistration> _reg) : reg{std::move(_reg)} {} + + void close() { + reg->unregister(); + } +private: + const std::shared_ptr<celix::ServiceRegistration> reg; +}; + +class StubImportServiceRegistration : public celix::rsa::IImportServiceRegistration { +public: + explicit StubImportServiceRegistration(std::weak_ptr<StubImportedServiceGuard> _guard) : guard{std::move(_guard)} {} + ~StubImportServiceRegistration() noexcept override { + auto g = guard.lock(); + if (g) { + g->close(); + } + } + +private: + const std::weak_ptr<StubImportedServiceGuard> guard; +}; + +class StubImportServiceFactory : public celix::rsa::IImportServiceFactory { +public: + explicit StubImportServiceFactory(std::shared_ptr<celix::BundleContext> _ctx) : ctx{std::move(_ctx)} {} + + virtual std::unique_ptr<celix::rsa::IImportServiceRegistration> importService(const celix::rsa::Endpoint& endpoint) { + if (endpoint.getExportedInterfaces() == celix::typeName<IDummyService>()) { + auto reg = ctx->registerService<IDummyService>(std::make_shared<DummyServiceImpl>()) + .addProperty(celix::rsa::REMOTE_SERVICE_IMPORTED_PROPERTY_NAME, true) + .build(); + std::lock_guard<std::mutex> lock{mutex}; + auto guard = std::make_shared<StubImportedServiceGuard>(std::move(reg)); + guards.emplace_back(guard); + return std::make_unique<StubImportServiceRegistration>(guard); + } else { + return {}; + } + } + +private: + const std::shared_ptr<celix::BundleContext> ctx; + std::mutex mutex{}; + std::vector<std::shared_ptr<StubImportedServiceGuard>> guards{}; +}; + +TEST_F(RemoteServiceAdminTestSuite, importService) { + auto bndId = ctx->installBundle(REMOTE_SERVICE_ADMIN_BUNDLE_LOCATION); + EXPECT_GE(bndId, 0); + + /** + * When I add a import service factory and register a Endpoint/ + * RemoteServiceAdmin will create a imported service (proxy for remote service described by the endpoint). + */ + auto count = ctx->useService<IDummyService>() + .build(); + EXPECT_EQ(0, count); + + auto reg1 = ctx->registerService<celix::rsa::IImportServiceFactory>(std::make_shared<StubImportServiceFactory>(ctx)) + .addProperty(celix::rsa::IImportServiceFactory::TARGET_SERVICE_NAME, celix::typeName<IDummyService>()) + .build(); + + count = ctx->useService<IDummyService>() + .build(); + EXPECT_EQ(0, count); + + auto endpoint = std::make_shared<celix::rsa::Endpoint>(celix::Properties{ + {celix::rsa::Endpoint::IDENTIFIER, "endpoint-id-1"}, + {celix::rsa::Endpoint::EXPORTS, celix::typeName<IDummyService>()}}); + auto reg2 = ctx->registerService<celix::rsa::Endpoint>(std::move(endpoint)) + .build(); + + //rsa called import service factory which created a IImportService, which register a IDummtService + count = ctx->useService<IDummyService>() + .build(); + EXPECT_EQ(1, count); + + + reg1->unregister(); + + //removed factory -> removed imported interface + count = ctx->useService<IDummyService>() + .build(); + EXPECT_EQ(0, count); +} \ No newline at end of file diff --git a/bundles/async_remote_services/admin/include/admin.h b/bundles/async_remote_services/admin/include/admin.h index cf5a58a..80be3ad 100644 --- a/bundles/async_remote_services/admin/include/admin.h +++ b/bundles/async_remote_services/admin/include/admin.h @@ -19,11 +19,7 @@ #include "celix/rsa/Endpoint.h" #include <celix_api.h> -#include <ImportedServiceFactory.h> -#include <ExportedServiceFactory.h> #include <mutex> -#include <pubsub/api.h> -#include <pubsub_message_serialization_service.h> #include "celix_log_service.h" #if defined(__has_include) && __has_include(<version>) @@ -32,45 +28,26 @@ #if __cpp_lib_memory_resource #include <memory_resource> +#include <celix/rsa/IImportServiceFactory.h> +#include <celix/rsa/IExportServiceFactory.h> + #endif namespace celix::async_rsa { - class AsyncAdmin; - - struct subscriber_handle { - subscriber_handle(long _svcId, AsyncAdmin *_admin, std::string_view _interface) : svcId(_svcId), admin(_admin), interface(_interface) {} - subscriber_handle(subscriber_handle const&) = default; - subscriber_handle(subscriber_handle&&) = default; - subscriber_handle& operator=(subscriber_handle const&) = default; - subscriber_handle& operator=(subscriber_handle&&) = default; - ~subscriber_handle() = default; - - long svcId; - AsyncAdmin *admin; - std::string interface; - }; class AsyncAdmin { public: - explicit AsyncAdmin(std::shared_ptr<celix::BundleContext> ctx) noexcept; - ~AsyncAdmin() noexcept = default; - - AsyncAdmin(AsyncAdmin const &) = delete; - AsyncAdmin(AsyncAdmin&&) = delete; - AsyncAdmin& operator=(AsyncAdmin const &) = delete; - AsyncAdmin& operator=(AsyncAdmin&&) = delete; - // Imported endpoint add/remove functions void addEndpoint(const std::shared_ptr<celix::rsa::Endpoint>& endpoint); void removeEndpoint(const std::shared_ptr<celix::rsa::Endpoint>& endpoint); - // Imported endpoint add/remove functions - void addImportedServiceFactory(const std::shared_ptr<celix::async_rsa::IImportedServiceFactory>& factory, const std::shared_ptr<const celix::Properties>& properties); - void removeImportedServiceFactory(const std::shared_ptr<celix::async_rsa::IImportedServiceFactory>& factory, const std::shared_ptr<const celix::Properties>& properties); + // import service factory. used to create new imported services + void addImportedServiceFactory(const std::shared_ptr<celix::rsa::IImportServiceFactory>& factory, const std::shared_ptr<const celix::Properties>& properties); + void removeImportedServiceFactory(const std::shared_ptr<celix::rsa::IImportServiceFactory>& factory, const std::shared_ptr<const celix::Properties>& properties); - // Exported endpoint add/remove functions - void addExportedServiceFactory(const std::shared_ptr<celix::async_rsa::IExportedServiceFactory>& factory, const std::shared_ptr<const celix::Properties>& properties); - void removeExportedServiceFactory(const std::shared_ptr<celix::async_rsa::IExportedServiceFactory>& factory, const std::shared_ptr<const celix::Properties>& properties); + // export service factory. used to create new exported services + void addExportedServiceFactory(const std::shared_ptr<celix::rsa::IExportServiceFactory>& factory, const std::shared_ptr<const celix::Properties>& properties); + void removeExportedServiceFactory(const std::shared_ptr<celix::rsa::IExportServiceFactory>& factory, const std::shared_ptr<const celix::Properties>& properties); // Add/remove services, used to track all services registered with celix and check if remote = true. void addService(const std::shared_ptr<void>& svc, const std::shared_ptr<const celix::Properties>& properties); @@ -82,23 +59,23 @@ namespace celix::async_rsa { void createExportServices(); void createImportServices(); - std::shared_ptr<celix::BundleContext> _ctx; std::shared_ptr<celix_log_service> _logService{}; std::mutex _m{}; // protects below #if __cpp_lib_memory_resource std::pmr::unsynchronized_pool_resource _memResource{}; - std::pmr::unordered_map<std::string, std::shared_ptr<celix::async_rsa::IExportedServiceFactory>> _exportedServiceFactories{&_memResource}; - std::pmr::unordered_map<std::string, std::shared_ptr<celix::async_rsa::IImportedServiceFactory>> _importedServiceFactories{&_memResource}; - std::pmr::unordered_map<std::string, std::string> _importedServiceInstances{&_memResource}; //key = endpoint id, value = cmp uuid. - std::pmr::unordered_map<long, std::string> _exportedServiceInstances{&_memResource}; //key = service id, value = cmp uuid. + + std::pmr::unordered_map<std::string, std::shared_ptr<celix::rsa::IExportServiceFactory>> _exportServiceFactories{&_memResource}; //key = service name + std::pmr::unordered_map<std::string, std::shared_ptr<celix::rsa::IImportServiceFactory>> _importServiceFactories{&_memResource}; //key = service name + std::pmr::unordered_map<std::string, std::unique_ptr<celix::rsa::IImportServiceRegistration>> _importedServices{&_memResource}; //key = endpoint id + std::pmr::unordered_map<long, std::unique_ptr<celix::rsa::IExportServiceRegistration>> _exportedServices{&_memResource}; //key = service id #else - std::unordered_map<std::string, std::shared_ptr<celix::async_rsa::IExportedServiceFactory>> _exportedServiceFactories{}; - std::unordered_map<std::string, std::shared_ptr<celix::async_rsa::IImportedServiceFactory>> _importedServiceFactories{}; - std::unordered_map<std::string, std::string> _importedServiceInstances{}; - std::unordered_map<long, std::string> _exportedServiceInstances{}; + std::unordered_map<std::string, std::shared_ptr<celix::rsa::IExportServiceFactory>> _exportServiceFactories{}; //key = service name + std::unordered_map<std::string, std::shared_ptr<celix::rsa::IImportServiceFactory>> _importServiceFactories{}; //key = service name + std::unordered_map<std::string, std::unique_ptr<celix::rsa::IImportServiceRegistration>> _importedServices{}; //key = endpoint id + std::unordered_map<long, std::unique_ptr<celix::rsa::IExportServiceRegistration>> _exportedServices{}; //key = service id #endif std::vector<std::shared_ptr<celix::rsa::Endpoint>> _toBeImportedServices{}; - std::vector<std::pair<std::shared_ptr<void>, std::shared_ptr<const celix::Properties>>> _toBeExportedServices{}; + std::vector<std::shared_ptr<const celix::Properties>> _toBeExportedServices{}; }; } \ No newline at end of file diff --git a/bundles/async_remote_services/admin/src/admin.cc b/bundles/async_remote_services/admin/src/admin.cc index c776599..3b92867 100644 --- a/bundles/async_remote_services/admin/src/admin.cc +++ b/bundles/async_remote_services/admin/src/admin.cc @@ -18,9 +18,6 @@ */ #include <admin.h> -#include <celix_api.h> -#include <pubsub_message_serialization_service.h> -#include <ConfiguredEndpoint.h> #include "celix/rsa/Constants.h" #define L_DEBUG(...) \ @@ -40,10 +37,6 @@ _logService->error(_logService->handle, __VA_ARGS__); \ } -celix::async_rsa::AsyncAdmin::AsyncAdmin(std::shared_ptr<celix::BundleContext> ctx) noexcept : _ctx{std::move(ctx)} { - -} - void celix::async_rsa::AsyncAdmin::addEndpoint(const std::shared_ptr<celix::rsa::Endpoint>& endpoint) { assert(endpoint); @@ -73,87 +66,89 @@ void celix::async_rsa::AsyncAdmin::removeEndpoint(const std::shared_ptr<celix::r return; } - std::lock_guard l(_m); - - _toBeImportedServices.erase(std::remove_if(_toBeImportedServices.begin(), _toBeImportedServices.end(), [&id](auto const &endpoint){ - return id == endpoint->getEndpointId(); - }), _toBeImportedServices.end()); + std::shared_ptr<celix::rsa::IImportServiceRegistration> tmpStore{}; //to ensure destruction outside of lock + { + std::lock_guard l(_m); + _toBeImportedServices.erase(std::remove_if(_toBeImportedServices.begin(), _toBeImportedServices.end(), [&id](auto const &endpoint){ + return id == endpoint->getEndpointId(); + }), _toBeImportedServices.end()); - auto instanceIt = _importedServiceInstances.find(id); - if (instanceIt == end(_importedServiceInstances)) { - return; + auto it = _importedServices.find(id); + if (it != _importedServices.end()) { + tmpStore = std::move(it->second); + _importedServices.erase(it); + } } - - _ctx->getDependencyManager()->removeComponentAsync(instanceIt->second); - _importedServiceInstances.erase(instanceIt); } -void celix::async_rsa::AsyncAdmin::addImportedServiceFactory(const std::shared_ptr<celix::async_rsa::IImportedServiceFactory>& factory, const std::shared_ptr<const celix::Properties>& properties) { - auto interface = properties->get(celix::rsa::Endpoint::EXPORTS); - - if (interface.empty()) { - L_DEBUG("Adding service factory but no exported interfaces"); +void celix::async_rsa::AsyncAdmin::addImportedServiceFactory( + const std::shared_ptr<celix::rsa::IImportServiceFactory> &factory, + const std::shared_ptr<const celix::Properties> &properties) { + auto targetServiceName = properties->get(celix::rsa::IImportServiceFactory::TARGET_SERVICE_NAME); + if (targetServiceName.empty()) { + L_WARN("Adding service factory but missing %s property", celix::rsa::IImportServiceFactory::TARGET_SERVICE_NAME); return; } - std::lock_guard l(_m); - auto existingFactory = _importedServiceFactories.find(interface); - if(existingFactory != end(_importedServiceFactories)) { + std::lock_guard l(_m); + auto existingFactory = _importServiceFactories.find(targetServiceName); + if (existingFactory != end(_importServiceFactories)) { L_WARN("Adding imported factory but factory already exists"); return; } - _importedServiceFactories.emplace(interface, factory); + _importServiceFactories.emplace(targetServiceName, factory); createImportServices(); } -void celix::async_rsa::AsyncAdmin::removeImportedServiceFactory(const std::shared_ptr<celix::async_rsa::IImportedServiceFactory>& /*factory*/, const std::shared_ptr<const celix::Properties>& properties) { - auto interface = properties->get(celix::rsa::Endpoint::EXPORTS); - - if (interface.empty()) { - L_WARN("Removing service factory but missing exported interfaces"); +void celix::async_rsa::AsyncAdmin::removeImportedServiceFactory( + const std::shared_ptr<celix::rsa::IImportServiceFactory> &/*factory*/, + const std::shared_ptr<const celix::Properties> &properties) { + auto targetServiceName = properties->get(celix::rsa::IImportServiceFactory::TARGET_SERVICE_NAME); + if (targetServiceName.empty()) { + L_WARN("Removing service factory but missing %s property", celix::rsa::IImportServiceFactory::TARGET_SERVICE_NAME); return; } std::lock_guard l(_m); - _importedServiceFactories.erase(interface); + _importServiceFactories.erase(targetServiceName); - //TODO TBD are the removal of the imported services also needed when a ImportedServiceFactory is removed (and maybe the bundle is uninstalled?) + //TODO remove imported services from this factory ??needed } -void celix::async_rsa::AsyncAdmin::addExportedServiceFactory(const std::shared_ptr<celix::async_rsa::IExportedServiceFactory>& factory, const std::shared_ptr<const celix::Properties>& properties) { - auto interface = properties->get(celix::rsa::Endpoint::EXPORTS); - - if (interface.empty()) { - L_WARN("Adding exported factory but missing exported interfaces"); +void celix::async_rsa::AsyncAdmin::addExportedServiceFactory( + const std::shared_ptr<celix::rsa::IExportServiceFactory> &factory, + const std::shared_ptr<const celix::Properties> &properties) { + auto targetServiceName = properties->get(celix::rsa::IExportServiceFactory::TARGET_SERVICE_NAME); + if (targetServiceName.empty()) { + L_WARN("Adding service factory but missing %s property", celix::rsa::IExportServiceFactory::TARGET_SERVICE_NAME); return; } std::lock_guard<std::mutex> lock{_m}; - _exportedServiceFactories.emplace(interface, factory); + _exportServiceFactories.emplace(targetServiceName, factory); createExportServices(); } -void celix::async_rsa::AsyncAdmin::removeExportedServiceFactory(const std::shared_ptr<celix::async_rsa::IExportedServiceFactory>& /*factory*/, const std::shared_ptr<const celix::Properties>& properties) { - auto interface = properties->get(celix::rsa::Endpoint::EXPORTS); - - if(interface.empty()) { - L_WARN("Removing imported factory but missing exported interfaces"); +void celix::async_rsa::AsyncAdmin::removeExportedServiceFactory( + const std::shared_ptr<celix::rsa::IExportServiceFactory> &/*factory*/, + const std::shared_ptr<const celix::Properties> &properties) { + auto targetServiceName = properties->get(celix::rsa::IExportServiceFactory::TARGET_SERVICE_NAME); + if (targetServiceName.empty()) { + L_WARN("Removing service factory but missing %s property", celix::rsa::IExportServiceFactory::TARGET_SERVICE_NAME); return; } std::lock_guard l(_m); - _exportedServiceFactories.erase(interface); + _exportServiceFactories.erase(targetServiceName); - //TODO TBD are the removal of the exported services also needed when a ExportedServiceFactory is removed (and maybe the bundle is uninstalled?) + //TODO remove exported services from this factory ??needed } -void celix::async_rsa::AsyncAdmin::addService(const std::shared_ptr<void>& svc, const std::shared_ptr<const celix::Properties>& props) { - assert(props->getAsBool(celix::rsa::REMOTE_SERVICE_PROPERTY_NAME, false)); //"only remote services should be tracker by the service tracker"); - +void celix::async_rsa::AsyncAdmin::addService(const std::shared_ptr<void>& /*svc*/, const std::shared_ptr<const celix::Properties>& props) { auto serviceName = props->get(celix::SERVICE_NAME, ""); if (serviceName.empty()) { L_WARN("Adding service to be exported but missing objectclass"); @@ -161,70 +156,71 @@ void celix::async_rsa::AsyncAdmin::addService(const std::shared_ptr<void>& svc, } std::lock_guard<std::mutex> lock{_m}; - _toBeExportedServices.emplace_back(svc, props); + _toBeExportedServices.emplace_back(props); createExportServices(); } void celix::async_rsa::AsyncAdmin::removeService(const std::shared_ptr<void>& /*svc*/, const std::shared_ptr<const celix::Properties>& props) { - assert(props->getAsBool(celix::rsa::REMOTE_SERVICE_PROPERTY_NAME, false)); //"only remote services should be tracker by the service tracker"); - long svcId = props->getAsLong(celix::SERVICE_ID, -1); if (svcId < 0) { L_WARN("Removing service to be exported but missing service.id"); return; } - std::lock_guard l(_m); + std::unique_ptr<celix::rsa::IExportServiceRegistration> tmpStore{}; //to ensure destruction outside of lock + { + std::lock_guard l(_m); - //remove export interface (if present) - auto instanceIt = _exportedServiceInstances.find(svcId); - if (instanceIt != end(_exportedServiceInstances)) { - //note cannot remove async, because the svc lifetime needs to extend the lifetime of the component. - //TODO improve by creating export service based on svc id instead of svc pointer, so that export service can track its own dependencies. - _ctx->getDependencyManager()->removeComponent(instanceIt->second); - _exportedServiceInstances.erase(instanceIt); - } + auto instanceIt = _exportedServices.find(svcId); + if (instanceIt != end(_exportedServices)) { + tmpStore = std::move(instanceIt->second); + _exportedServices.erase(instanceIt); + } - //remove to be exported endpoint (if present) - for (auto it = _toBeExportedServices.begin(); it != _toBeExportedServices.end(); ++it) { - if (it->second->getAsBool(celix::SERVICE_ID, -1) == svcId) { - _toBeExportedServices.erase(it); - break; + //remove to be exported endpoint (if present) + for (auto it = _toBeExportedServices.begin(); it != _toBeExportedServices.end(); ++it) { + if ((*it)->getAsBool(celix::SERVICE_ID, -1) == svcId) { + _toBeExportedServices.erase(it); + break; + } } } - } void celix::async_rsa::AsyncAdmin::createImportServices() { - for (auto it = _toBeImportedServices.begin(); it != _toBeImportedServices.end(); ++it) { + auto it = _toBeImportedServices.begin(); + while (it != _toBeImportedServices.end()) { auto interface = (*it)->getExportedInterfaces(); - auto existingFactory = _importedServiceFactories.find(interface); - if (existingFactory == end(_importedServiceFactories)) { + auto existingFactory = _importServiceFactories.find(interface); + if (existingFactory == end(_importServiceFactories)) { L_DEBUG("Adding endpoint to be imported but no factory available yet, delaying import"); + ++it; + continue; } auto endpointId = (*it)->getEndpointId(); L_DEBUG("Adding endpoint, created service"); - _importedServiceInstances.emplace(endpointId, existingFactory->second->create(endpointId).getUUID()); + _importedServices.emplace(endpointId, existingFactory->second->importService(**it)); it = _toBeImportedServices.erase(it); } } void celix::async_rsa::AsyncAdmin::createExportServices() { - for (auto it = _toBeExportedServices.begin(); it != _toBeExportedServices.end(); ++it) { - auto serviceName = it->second->get(celix::SERVICE_NAME, ""); - auto svcId = it->second->getAsLong(celix::SERVICE_ID, -1); + auto it = _toBeExportedServices.begin(); + while (it != _toBeExportedServices.end()) { + const auto& svcProperties = **it; + auto serviceName = svcProperties.get(celix::SERVICE_NAME, ""); + auto svcId = svcProperties.getAsLong(celix::SERVICE_ID, -1); if (serviceName.empty()) { L_WARN("Adding service to be exported but missing objectclass for svc id %li", svcId); continue; } - auto factory = _exportedServiceFactories.find(serviceName); - if (factory == end(_exportedServiceFactories)) { + auto factory = _exportServiceFactories.find(serviceName); + if (factory == end(_exportServiceFactories)) { L_DEBUG("Adding service to be exported but no factory available yet, delaying creation"); + ++it; continue; } - auto endpointId = _ctx->getFramework()->getUUID() + "-" + std::to_string(svcId); - auto cmpUUID = factory->second->create(it->first.get(), std::move(endpointId)).getUUID(); - _exportedServiceInstances.emplace(svcId, std::move(cmpUUID)); + _exportedServices.emplace(svcId, factory->second->exportService(svcProperties)); it = _toBeExportedServices.erase(it); } } @@ -236,18 +232,18 @@ void celix::async_rsa::AsyncAdmin::setLogger(const std::shared_ptr<celix_log_ser class AdminActivator { public: explicit AdminActivator(const std::shared_ptr<celix::BundleContext>& ctx) { - auto admin = std::make_shared<celix::async_rsa::AsyncAdmin>(ctx); + auto admin = std::make_shared<celix::async_rsa::AsyncAdmin>(); auto& cmp = ctx->getDependencyManager()->createComponent(admin); cmp.createServiceDependency<celix::rsa::Endpoint>() .setRequired(false) .setStrategy(celix::dm::DependencyUpdateStrategy::locking) .setCallbacks(&celix::async_rsa::AsyncAdmin::addEndpoint, &celix::async_rsa::AsyncAdmin::removeEndpoint); - cmp.createServiceDependency<celix::async_rsa::IImportedServiceFactory>() + cmp.createServiceDependency<celix::rsa::IImportServiceFactory>() .setRequired(false) .setStrategy(celix::dm::DependencyUpdateStrategy::locking) .setCallbacks(&celix::async_rsa::AsyncAdmin::addImportedServiceFactory, &celix::async_rsa::AsyncAdmin::removeImportedServiceFactory); - cmp.createServiceDependency<celix::async_rsa::IExportedServiceFactory>() + cmp.createServiceDependency<celix::rsa::IExportServiceFactory>() .setRequired(false) .setStrategy(celix::dm::DependencyUpdateStrategy::locking) .setCallbacks(&celix::async_rsa::AsyncAdmin::addExportedServiceFactory, &celix::async_rsa::AsyncAdmin::removeExportedServiceFactory); @@ -259,8 +255,8 @@ public: cmp.build(); //note adding void service dependencies is not supported for the dependency manager, using a service tracker instead. - _remoteServiceTracker = ctx->trackServices<void>() - .setFilter(std::string{"("}.append(celix::rsa::REMOTE_SERVICE_PROPERTY_NAME).append("=*)")) + _remoteServiceTracker = ctx->trackAnyServices() + .setFilter(std::string{"("}.append(celix::rsa::REMOTE_SERVICE_EXPORTED_PROPERTY_NAME).append("=*)")) .addAddWithPropertiesCallback([admin](const std::shared_ptr<void>& svc, const std::shared_ptr<const celix::Properties>& properties) { admin->addService(svc, properties); }) diff --git a/bundles/async_remote_services/common/CMakeLists.txt b/bundles/async_remote_services/common/CMakeLists.txt index 979305c..42888bd 100644 --- a/bundles/async_remote_services/common/CMakeLists.txt +++ b/bundles/async_remote_services/common/CMakeLists.txt @@ -21,6 +21,7 @@ target_include_directories(async_rsa_common INTERFACE $<INSTALL_INTERFACE:include/celix/async_rsa_common> ) target_compile_options(async_rsa_common INTERFACE -std=c++17) +target_link_libraries(async_rsa_common INTERFACE Celix::pubsub_spi Celix::pubsub_api Celix::rsa_spi) #set_target_properties(async_rsa_common PROPERTIES OUTPUT_NAME "celix_async_rsa_common") #target_include_directories(async_rsa_common PRIVATE src) #target_link_libraries(async_rsa_common INTERFACE Celix::framework) diff --git a/bundles/async_remote_services/common/include/ImportedServiceFactory.h b/bundles/async_remote_services/common/include/ImportedServiceFactory.h index 5783d47..6a342f7 100644 --- a/bundles/async_remote_services/common/include/ImportedServiceFactory.h +++ b/bundles/async_remote_services/common/include/ImportedServiceFactory.h @@ -19,7 +19,6 @@ #pragma once #include <celix/dm/DependencyManager.h> -#include <pubsub_endpoint.h> namespace celix::async_rsa { /// Service factory interface. diff --git a/bundles/async_remote_services/examples/CMakeLists.txt b/bundles/async_remote_services/examples/CMakeLists.txt index 0935068..3aa8ee4 100644 --- a/bundles/async_remote_services/examples/CMakeLists.txt +++ b/bundles/async_remote_services/examples/CMakeLists.txt @@ -48,8 +48,8 @@ celix_bundle_files(hardcoded_example_subscriber DESTINATION "META-INF/topics/sub" ) -target_link_libraries(hardcoded_example_provider PRIVATE Celix::framework Celix::async_rsa_discovery_configured Celix::async_rsa_common Celix::async_rsa) -target_link_libraries(hardcoded_example_subscriber PRIVATE Celix::framework Celix::async_rsa_discovery_configured Celix::async_rsa_common Celix::async_rsa) +target_link_libraries(hardcoded_example_provider PRIVATE Celix::framework Celix::async_rsa_common) +target_link_libraries(hardcoded_example_subscriber PRIVATE Celix::framework Celix::async_rsa_common) target_compile_options(hardcoded_example_provider INTERFACE -std=c++17) target_compile_options(hardcoded_example_subscriber INTERFACE -std=c++17) @@ -78,7 +78,7 @@ add_celix_container(hardcoded_example_provider_cnt Celix::pubsub_protocol_wire_v2 Celix::async_rsa_discovery_configured Celix::async_topology_manager - Celix::async_rsa + Celix::RemoteServiceAdmin hardcoded_example_provider PROPERTIES "org.osgi.framework.storage=.publisherCache" @@ -99,7 +99,7 @@ add_celix_container(hardcoded_example_subscriber_cnt Celix::pubsub_protocol_wire_v2 Celix::async_rsa_discovery_configured Celix::async_topology_manager - Celix::async_rsa + Celix::RemoteServiceAdmin hardcoded_example_subscriber PROPERTIES "org.osgi.framework.storage=.subscriberCache" diff --git a/bundles/async_remote_services/rsa_spi/CMakeLists.txt b/bundles/async_remote_services/rsa_spi/CMakeLists.txt index 33ed0a5..47568ff 100644 --- a/bundles/async_remote_services/rsa_spi/CMakeLists.txt +++ b/bundles/async_remote_services/rsa_spi/CMakeLists.txt @@ -20,7 +20,6 @@ target_include_directories(rsa_spi INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include> $<INSTALL_INTERFACE:include/celix/rsa> ) -target_link_libraries(rsa_spi INTERFACE Celix::async_rsa_discovery_configured) target_compile_options(rsa_spi INTERFACE -std=c++17) install(TARGETS rsa_spi EXPORT celix DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT rsa) diff --git a/bundles/async_remote_services/rsa_spi/include/celix/rsa/Constants.h b/bundles/async_remote_services/rsa_spi/include/celix/rsa/Constants.h index 2b5d0c4..5ae1c9f 100644 --- a/bundles/async_remote_services/rsa_spi/include/celix/rsa/Constants.h +++ b/bundles/async_remote_services/rsa_spi/include/celix/rsa/Constants.h @@ -23,9 +23,15 @@ namespace celix::rsa { /** - * @brief Service property (named "remote") to mark a service as a remote service. + * @brief Service property (named "service.exported") to mark a service as wanting to be exported (remote). * Present means -> export service as a remote service. */ - constexpr const char *const REMOTE_SERVICE_PROPERTY_NAME = "remote"; + constexpr const char * const REMOTE_SERVICE_EXPORTED_PROPERTY_NAME = "service.exported"; + + /** + * @brief Service property (named "remote") to mark a service as a imported service. + * Present means -> service is a imported service (proxy of a remote service). + */ + constexpr const char * const REMOTE_SERVICE_IMPORTED_PROPERTY_NAME = "service.imported"; } \ No newline at end of file diff --git a/bundles/async_remote_services/rsa_spi/include/celix/rsa/Endpoint.h b/bundles/async_remote_services/rsa_spi/include/celix/rsa/Endpoint.h index 97a81da..6035823 100644 --- a/bundles/async_remote_services/rsa_spi/include/celix/rsa/Endpoint.h +++ b/bundles/async_remote_services/rsa_spi/include/celix/rsa/Endpoint.h @@ -31,12 +31,12 @@ namespace celix::rsa { class Endpoint { public: static constexpr const char * const IDENTIFIER = "endpoint.id"; - static constexpr const char * const IMPORTED = "service.imported"; - static constexpr const char * const IMPORT_CONFIGS = "service.imported.configs"; +// static constexpr const char * const IMPORTED = "service.imported"; +// static constexpr const char * const IMPORT_CONFIGS = "service.imported.configs"; static constexpr const char * const EXPORTS = "service.exported.interfaces"; - static constexpr const char * const OBJECTCLASS = "endpoint.objectClass"; - static constexpr const char * const SCOPE = "endpoint.scope"; - static constexpr const char * const TOPIC = "endpoint.topic"; +// static constexpr const char * const OBJECTCLASS = "endpoint.objectClass"; +// static constexpr const char * const SCOPE = "endpoint.scope"; +// static constexpr const char * const TOPIC = "endpoint.topic"; /** @@ -59,8 +59,6 @@ namespace celix::rsa { return _celixProperties.get(EXPORTS); } - - protected: celix::dm::Properties _celixProperties; diff --git a/bundles/async_remote_services/rsa_spi/include/celix/rsa/IExportServiceFactory.h b/bundles/async_remote_services/rsa_spi/include/celix/rsa/IExportServiceFactory.h index b0a4c96..fa5508c 100644 --- a/bundles/async_remote_services/rsa_spi/include/celix/rsa/IExportServiceFactory.h +++ b/bundles/async_remote_services/rsa_spi/include/celix/rsa/IExportServiceFactory.h @@ -19,21 +19,17 @@ #pragma once #include <memory> +#include "celix/rsa/Endpoint.h" namespace celix::rsa { /** - * @brief ExportService class which represent a (opaque) exported service. + * @brief ExportServiceRegistration class which represent a (opaque) exported service. * The lifetime of this object should be coupled with the lifetime of the exported service. */ - class ExportedService { + class IExportServiceRegistration { public: - virtual ~ExportedService() noexcept = default; - - /** - * @brief returns the endpoint for this exported service (to be used in discovery). - */ - virtual const celix::rsa::Endpoint& getEndpoint() const = 0; + virtual ~IExportServiceRegistration() noexcept = default; }; /** @@ -45,14 +41,12 @@ namespace celix::rsa { */ class IExportServiceFactory { public: - static constexpr std::string_view TARGET_SERVICE_NAME = "target.service.name"; - - virtual ~IExportServiceFactory() noexcept = default; - /** * @brief The service name for which this factory can created exported services. */ - std::string& const getTargetServiceName() const = 0; + static constexpr const char * const TARGET_SERVICE_NAME = "target.service.name"; + + virtual ~IExportServiceFactory() noexcept = default; /** * @brief Exports the service identified with svcId @@ -60,6 +54,6 @@ namespace celix::rsa { * @return A ExportService. * @throws celix::rsa::RemoteServicesException if the export failed. */ - virtual std::unique_ptr<ExportedService> exportService(const celix::Properties& serviceProperties) = 0; + virtual std::unique_ptr<celix::rsa::IExportServiceRegistration> exportService(const celix::Properties& serviceProperties) = 0; }; } \ No newline at end of file diff --git a/bundles/async_remote_services/rsa_spi/include/celix/rsa/IImportServiceFactory.h b/bundles/async_remote_services/rsa_spi/include/celix/rsa/IImportServiceFactory.h index 9427146..f62cf23 100644 --- a/bundles/async_remote_services/rsa_spi/include/celix/rsa/IImportServiceFactory.h +++ b/bundles/async_remote_services/rsa_spi/include/celix/rsa/IImportServiceFactory.h @@ -19,21 +19,17 @@ #pragma once #include <memory> +#include "celix/rsa/Endpoint.h" namespace celix::rsa { /** - * @brief ImportService class which represent a (opaque) imported service. + * @brief ImportServiceRegistration class which represent a (opaque) imported service. * The lifetime of this object should be coupled with the lifetime of the imported service. */ - class ImportedService { + class IImportServiceRegistration { public: - virtual ~ImportedService() noexcept = default; - - /** - * @brief returns the endpoint used for this imported service. - */ - virtual const celix::rsa::Endpoint& getEndpoint() const = 0; + virtual ~IImportServiceRegistration() noexcept = default; }; /** @@ -45,14 +41,12 @@ namespace celix::rsa { */ class IImportServiceFactory { public: - static constexpr std::string_view TARGET_SERVICE_NAME = "target.service.name"; - - virtual ~IImportServiceFactory() noexcept = default; - /** * @brief The service name for which this factory can created exported services. */ - std::string& const getTargetServiceName() const = 0; + static constexpr const char * const TARGET_SERVICE_NAME = "target.service.name"; + + virtual ~IImportServiceFactory() noexcept = default; /** * @brief Imports the service identified with svcId @@ -60,6 +54,6 @@ namespace celix::rsa { * @return A ImportService. * @throws celix::rsa::RemoteServicesException if the import failed. */ - virtual std::unique_ptr<ImportedService> importService(const celix::rsa::Endpoint& endpoint) = 0; + virtual std::unique_ptr<celix::rsa::IImportServiceRegistration> importService(const celix::rsa::Endpoint& endpoint) = 0; }; } \ No newline at end of file diff --git a/libs/framework/include/celix/ServiceRegistration.h b/libs/framework/include/celix/ServiceRegistration.h index 38981b0..d3e4d0c 100644 --- a/libs/framework/include/celix/ServiceRegistration.h +++ b/libs/framework/include/celix/ServiceRegistration.h @@ -208,6 +208,7 @@ namespace celix { { std::lock_guard<std::mutex> lck{reg->mutex}; reg->state = ServiceRegistrationState::UNREGISTERED; + reg->svc.reset(); } for (const auto &cb : reg->onUnregisteredCallbacks) { cb(*reg); @@ -229,6 +230,7 @@ namespace celix { { std::lock_guard<std::mutex> lck{mutex}; state = ServiceRegistrationState::UNREGISTERED; + svc.reset(); } for (const auto& cb: onUnregisteredCallbacks) { cb(*this); @@ -262,14 +264,14 @@ namespace celix { std::vector<std::function<void(ServiceRegistration&)>> _onRegisteredCallbacks, std::vector<std::function<void(ServiceRegistration&)>> _onUnregisteredCallbacks) : cCtx{std::move(_cCtx)}, - svc{std::move(_svc)}, name{std::move(_name)}, version{std::move(_version)}, properties{std::move(_properties)}, registerAsync{_registerAsync}, unregisterAsync{_unregisterAsync}, onRegisteredCallbacks{std::move(_onRegisteredCallbacks)}, - onUnregisteredCallbacks{std::move(_onUnregisteredCallbacks)} {} + onUnregisteredCallbacks{std::move(_onUnregisteredCallbacks)}, + svc{std::move(_svc)} {} /** @@ -333,7 +335,6 @@ namespace celix { } 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; @@ -344,6 +345,7 @@ namespace celix { mutable std::mutex mutex{}; //protects below long svcId{-1}; + std::shared_ptr<void> svc; ServiceRegistrationState state{ServiceRegistrationState::REGISTERING}; std::weak_ptr<ServiceRegistration> self{}; //weak ptr to self, so that callbacks can receive a shared ptr }; diff --git a/libs/framework/include/celix/dm/DependencyManager_Impl.h b/libs/framework/include/celix/dm/DependencyManager_Impl.h index 86a90c7..6ff1da2 100644 --- a/libs/framework/include/celix/dm/DependencyManager_Impl.h +++ b/libs/framework/include/celix/dm/DependencyManager_Impl.h @@ -27,7 +27,7 @@ inline DependencyManager::DependencyManager(celix_bundle_context_t *ctx) : cDepMan{celix_bundleContext_getDependencyManager(ctx), [](celix_dependency_manager_t*){/*nop*/}} {} inline DependencyManager::~DependencyManager() { - clear(); + clearAsync(); } template<class T>
