This is an automated email from the ASF dual-hosted git repository. pnoltes pushed a commit to branch feature/add_intent_to_cxx_rsa in repository https://gitbox.apache.org/repos/asf/celix.git
commit 36b1f6f1c633b04ef6c9d73f4fe3c480c0dc5e55 Author: Pepijn Noltes <[email protected]> AuthorDate: Tue Jun 1 21:50:15 2021 +0200 Adds support for remote intents and configs on the import/export service factories. --- bundles/cxx_remote_services/admin/CMakeLists.txt | 2 +- .../admin/gtest/src/RemoteServiceAdminTestSuite.cc | 55 ++++-- .../admin/src/RemoteServiceAdmin.cc | 218 +++++++++++---------- .../admin/{include => src}/RemoteServiceAdmin.h | 38 ++-- .../admin/src/RemoteServiceAdminActivator.cc | 63 ++++++ .../gtest/src/RsaConfiguredDiscoveryTestSuite.cc | 2 +- .../integration/src/CalculatorProvider.cc | 3 +- .../src/TestExportImportRemoteServiceFactory.cc | 54 +++-- .../include/celix/rsa/EndpointDescription.h | 46 +++-- .../include/celix/rsa/IExportRegistration.h | 31 +++ .../include/celix/rsa/IExportServiceFactory.h | 40 ++-- .../include/celix/rsa/IImportRegistration.h | 31 +++ .../include/celix/rsa/IImportServiceFactory.h | 36 ++-- .../rsa_spi/include/celix/rsa/RemoteConstants.h | 2 +- .../logging/log_helper/include/celix/LogHelper.h | 14 +- 15 files changed, 438 insertions(+), 197 deletions(-) diff --git a/bundles/cxx_remote_services/admin/CMakeLists.txt b/bundles/cxx_remote_services/admin/CMakeLists.txt index 4a6dac3..24b77ab 100644 --- a/bundles/cxx_remote_services/admin/CMakeLists.txt +++ b/bundles/cxx_remote_services/admin/CMakeLists.txt @@ -23,8 +23,8 @@ add_celix_bundle(RemoteServiceAdmin FILENAME "Celix_RemoteServiceAdmin" SOURCES src/RemoteServiceAdmin.cc + src/RemoteServiceAdminActivator.cc ) -target_include_directories(RemoteServiceAdmin PRIVATE include) target_link_libraries(RemoteServiceAdmin PRIVATE Celix::rsa_spi Celix::framework diff --git a/bundles/cxx_remote_services/admin/gtest/src/RemoteServiceAdminTestSuite.cc b/bundles/cxx_remote_services/admin/gtest/src/RemoteServiceAdminTestSuite.cc index 3ffdd18..a9b4d49 100644 --- a/bundles/cxx_remote_services/admin/gtest/src/RemoteServiceAdminTestSuite.cc +++ b/bundles/cxx_remote_services/admin/gtest/src/RemoteServiceAdminTestSuite.cc @@ -87,7 +87,7 @@ private: std::string cmpUUID{}; }; -class StubExportServiceGuard : public celix::rsa::IExportServiceGuard { +class StubExportServiceGuard : public celix::rsa::IExportRegistration { public: explicit StubExportServiceGuard(std::weak_ptr<StubExportedServiceEntry> _entry) : entry{std::move(_entry)} {} ~StubExportServiceGuard() noexcept override { @@ -101,28 +101,45 @@ private: const std::weak_ptr<StubExportedServiceEntry> entry; }; +class IDummyService { +public: + virtual ~IDummyService() noexcept = default; +}; + class StubExportServiceFactory : public celix::rsa::IExportServiceFactory { public: explicit StubExportServiceFactory(std::shared_ptr<celix::BundleContext> _ctx) : ctx{std::move(_ctx)} {} + ~StubExportServiceFactory() noexcept override = default; - std::unique_ptr<celix::rsa::IExportServiceGuard> exportService(const celix::Properties& /*serviceProperties*/) override { + std::unique_ptr<celix::rsa::IExportRegistration> exportService(const celix::Properties& /*serviceProperties*/) override { auto entry = std::make_shared<StubExportedServiceEntry>(ctx); std::lock_guard<std::mutex> lock{mutex}; entries.emplace_back(entry); return std::make_unique<StubExportServiceGuard>(entry); } + + const std::string &getRemoteServiceType() const override { + return serviceType; + } + + const std::vector<std::string> &getSupportedIntents() const override { + return intents; + } + + const std::vector<std::string> &getSupportedConfigs() const override { + return configs; + } + private: + const std::string serviceType = celix::typeName<IDummyService>(); + const std::vector<std::string> configs = {"test"}; + const std::vector<std::string> intents = {"osgi.basic"}; const std::shared_ptr<celix::BundleContext> ctx; std::mutex mutex{}; std::vector<std::shared_ptr<StubExportedServiceEntry>> entries{}; }; -class IDummyService { -public: - virtual ~IDummyService() noexcept = default; -}; - class DummyServiceImpl : public IDummyService { public: ~DummyServiceImpl() noexcept override = default; @@ -141,7 +158,7 @@ TEST_F(RemoteServiceAdminTestSuite, exportService) { 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>()) + .addProperty(celix::rsa::IExportServiceFactory::REMOTE_SERVICE_TYPE, celix::typeName<IDummyService>()) .build(); count = ctx->useService<celix::rsa::IExportedService>() @@ -190,7 +207,7 @@ TEST_F(RemoteServiceAdminTestSuite, exportServiceDifferentOrder) { 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>()) + .addProperty(celix::rsa::IExportServiceFactory::REMOTE_SERVICE_TYPE, celix::typeName<IDummyService>()) .build(); //rsa called export service factory which created a IExportServiceRegistration, which register the marker interface IExportedService indicating an exported service @@ -237,7 +254,7 @@ private: std::string cmpUUID{}; }; -class StubImportServiceGuard : public celix::rsa::IImportServiceGuard { +class StubImportServiceGuard : public celix::rsa::IImportRegistration { public: explicit StubImportServiceGuard(std::weak_ptr<StubImportedServiceEntry> _entry) : entry{std::move(_entry)} {} ~StubImportServiceGuard() noexcept override { @@ -254,8 +271,9 @@ private: class StubImportServiceFactory : public celix::rsa::IImportServiceFactory { public: explicit StubImportServiceFactory(std::shared_ptr<celix::BundleContext> _ctx) : ctx{std::move(_ctx)} {} + ~StubImportServiceFactory() noexcept override = default; - virtual std::unique_ptr<celix::rsa::IImportServiceGuard> importService(const celix::rsa::EndpointDescription& endpoint) { + [[nodiscard]] std::unique_ptr<celix::rsa::IImportRegistration> importService(const celix::rsa::EndpointDescription& endpoint) override { if (endpoint.getInterface() == celix::typeName<IDummyService>()) { std::lock_guard<std::mutex> lock{mutex}; auto entry = std::make_shared<StubImportedServiceEntry>(ctx); @@ -266,7 +284,17 @@ public: } } + [[nodiscard]] const std::string &getRemoteServiceType() const override { + return serviceType; + } + + [[nodiscard]] const std::vector<std::string> &getSupportedConfigs() const override { + return configs; + } + private: + const std::string serviceType{celix::typeName<IDummyService>()}; + const std::vector<std::string> configs{"test"}; const std::shared_ptr<celix::BundleContext> ctx; std::mutex mutex{}; std::vector<std::shared_ptr<StubImportedServiceEntry>> entries{}; @@ -285,7 +313,7 @@ TEST_F(RemoteServiceAdminTestSuite, importService) { 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>()) + .addProperty(celix::rsa::IImportServiceFactory::REMOTE_SERVICE_TYPE, celix::typeName<IDummyService>()) .build(); count = ctx->useService<IDummyService>() @@ -294,7 +322,8 @@ TEST_F(RemoteServiceAdminTestSuite, importService) { auto endpoint = std::make_shared<celix::rsa::EndpointDescription>(celix::Properties{ {celix::rsa::ENDPOINT_ID, "endpoint-id-1"}, - {celix::SERVICE_NAME,celix::typeName<IDummyService>()}}); + {celix::SERVICE_NAME,celix::typeName<IDummyService>()}, + {celix::rsa::SERVICE_IMPORTED_CONFIGS, "test"}}); auto reg2 = ctx->registerService<celix::rsa::EndpointDescription>(std::move(endpoint)) .build(); diff --git a/bundles/cxx_remote_services/admin/src/RemoteServiceAdmin.cc b/bundles/cxx_remote_services/admin/src/RemoteServiceAdmin.cc index 207feec..3f2206d 100644 --- a/bundles/cxx_remote_services/admin/src/RemoteServiceAdmin.cc +++ b/bundles/cxx_remote_services/admin/src/RemoteServiceAdmin.cc @@ -19,21 +19,20 @@ #include "RemoteServiceAdmin.h" #include "celix/BundleContext.h" -#include "celix/BundleActivator.h" #include "celix/rsa/RemoteConstants.h" -#include "celix/rsa/IImportServiceFactory.h" -#include "celix/rsa/IExportServiceFactory.h" +#define L_TRACE(...) \ + logHelper.trace(__VA_ARGS__); #define L_DEBUG(...) \ - _logHelper.debug(__VA_ARGS__); + logHelper.debug(__VA_ARGS__); #define L_INFO(...) \ _logHelper.info(__VA_ARGS__); #define L_WARN(...) \ - _logHelper.warning(__VA_ARGS__); + logHelper.warning(__VA_ARGS__); #define L_ERROR(...) \ _logHelper.error(__VA_ARGS__); -celix::rsa::RemoteServiceAdmin::RemoteServiceAdmin(celix::LogHelper logHelper) : _logHelper{std::move(logHelper)} {} +celix::rsa::RemoteServiceAdmin::RemoteServiceAdmin(celix::LogHelper logHelper) : logHelper{std::move(logHelper)} {} void celix::rsa::RemoteServiceAdmin::addEndpoint(const std::shared_ptr<celix::rsa::EndpointDescription>& endpoint) { assert(endpoint); @@ -50,8 +49,8 @@ void celix::rsa::RemoteServiceAdmin::addEndpoint(const std::shared_ptr<celix::rs return; } - std::lock_guard l(_m); - _toBeImportedServices.emplace_back(endpoint); + std::lock_guard l(mutex); + toBeImportedServices.emplace_back(endpoint); createImportServices(); } @@ -64,18 +63,18 @@ void celix::rsa::RemoteServiceAdmin::removeEndpoint(const std::shared_ptr<celix: return; } - std::shared_ptr<celix::rsa::IImportServiceGuard> tmpStore{}; //to ensure destruction outside of lock + std::shared_ptr<celix::rsa::IImportRegistration> tmpStore{}; //to ensure destruction outside of lock { - std::lock_guard l(_m); + std::lock_guard l(mutex); - _toBeImportedServices.erase(std::remove_if(_toBeImportedServices.begin(), _toBeImportedServices.end(), [&id](auto const &endpoint){ + toBeImportedServices.erase(std::remove_if(toBeImportedServices.begin(), toBeImportedServices.end(), [&id](auto const &endpoint){ return id == endpoint->getId(); - }), _toBeImportedServices.end()); + }), toBeImportedServices.end()); - auto it = _importedServices.find(id); - if (it != _importedServices.end()) { + auto it = importedServices.find(id); + if (it != importedServices.end()) { tmpStore = std::move(it->second); - _importedServices.erase(it); + importedServices.erase(it); } } } @@ -83,21 +82,21 @@ void celix::rsa::RemoteServiceAdmin::removeEndpoint(const std::shared_ptr<celix: void celix::rsa::RemoteServiceAdmin::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); + auto targetServiceName = properties->get(celix::rsa::IImportServiceFactory::REMOTE_SERVICE_TYPE); if (targetServiceName.empty()) { - L_WARN("Adding service factory but missing %s property", celix::rsa::IImportServiceFactory::TARGET_SERVICE_NAME); + L_WARN("Adding service factory but missing %s property", celix::rsa::IImportServiceFactory::REMOTE_SERVICE_TYPE); return; } - std::lock_guard l(_m); - auto existingFactory = _importServiceFactories.find(targetServiceName); - if (existingFactory != end(_importServiceFactories)) { + std::lock_guard l(mutex); + auto existingFactory = importServiceFactories.find(targetServiceName); + if (existingFactory != end(importServiceFactories)) { L_WARN("Adding imported factory but factory already exists"); return; } - _importServiceFactories.emplace(targetServiceName, factory); + importServiceFactories.emplace(targetServiceName, factory); createImportServices(); } @@ -105,14 +104,14 @@ void celix::rsa::RemoteServiceAdmin::addImportedServiceFactory( void celix::rsa::RemoteServiceAdmin::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); + auto targetServiceName = properties->get(celix::rsa::IImportServiceFactory::REMOTE_SERVICE_TYPE); if (targetServiceName.empty()) { - L_WARN("Removing service factory but missing %s property", celix::rsa::IImportServiceFactory::TARGET_SERVICE_NAME); + L_WARN("Removing service factory but missing %s property", celix::rsa::IImportServiceFactory::REMOTE_SERVICE_TYPE); return; } - std::lock_guard l(_m); - _importServiceFactories.erase(targetServiceName); + std::lock_guard l(mutex); + importServiceFactories.erase(targetServiceName); //TODO remove imported services from this factory ??needed } @@ -120,28 +119,28 @@ void celix::rsa::RemoteServiceAdmin::removeImportedServiceFactory( void celix::rsa::RemoteServiceAdmin::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); + auto targetServiceName = properties->get(celix::rsa::IExportServiceFactory::REMOTE_SERVICE_TYPE); if (targetServiceName.empty()) { - L_WARN("Adding service factory but missing %s property", celix::rsa::IExportServiceFactory::TARGET_SERVICE_NAME); + L_WARN("Adding service factory but missing %s property", celix::rsa::IExportServiceFactory::REMOTE_SERVICE_TYPE); return; } - std::lock_guard<std::mutex> lock{_m}; - _exportServiceFactories.emplace(targetServiceName, factory); + std::lock_guard<std::mutex> lock{mutex}; + exportServiceFactories.emplace(targetServiceName, factory); createExportServices(); } void celix::rsa::RemoteServiceAdmin::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); + auto targetServiceName = properties->get(celix::rsa::IExportServiceFactory::REMOTE_SERVICE_TYPE); if (targetServiceName.empty()) { - L_WARN("Removing service factory but missing %s property", celix::rsa::IExportServiceFactory::TARGET_SERVICE_NAME); + L_WARN("Removing service factory but missing %s property", celix::rsa::IExportServiceFactory::REMOTE_SERVICE_TYPE); return; } - std::lock_guard l(_m); - _exportServiceFactories.erase(targetServiceName); + std::lock_guard l(mutex); + exportServiceFactories.erase(targetServiceName); //TODO remove exported services from this factory ??needed } @@ -153,8 +152,8 @@ void celix::rsa::RemoteServiceAdmin::addService(const std::shared_ptr<void>& /*s return; } - std::lock_guard<std::mutex> lock{_m}; - _toBeExportedServices.emplace_back(props); + std::lock_guard<std::mutex> lock{mutex}; + toBeExportedServices.emplace_back(props); createExportServices(); } @@ -165,94 +164,107 @@ void celix::rsa::RemoteServiceAdmin::removeService(const std::shared_ptr<void>& return; } - std::lock_guard l(_m); + std::lock_guard l(mutex); - auto instanceIt = _exportedServices.find(svcId); - if (instanceIt != end(_exportedServices)) { - _exportedServices.erase(instanceIt); + auto instanceIt = exportedServices.find(svcId); + if (instanceIt != end(exportedServices)) { + exportedServices.erase(instanceIt); } //remove to be exported endpoint (if present) - for (auto it = _toBeExportedServices.begin(); it != _toBeExportedServices.end(); ++it) { + for (auto it = toBeExportedServices.begin(); it != toBeExportedServices.end(); ++it) { if ((*it)->getAsLong(celix::SERVICE_ID, -1) == svcId) { - _toBeExportedServices.erase(it); + toBeExportedServices.erase(it); break; } } } +bool celix::rsa::RemoteServiceAdmin::isEndpointMatch(const celix::rsa::EndpointDescription& endpoint, const celix::rsa::IImportServiceFactory& factory) const { + if (factory.getSupportedConfigs().empty()) { + L_WARN("Matching endpoint with a import service factory with no supported configs, this will always fail"); + return false; + } + if (endpoint.getConfigurationTypes().empty()) { + L_WARN("Matching endpoint with configuration types (%s), this will always fail", celix::rsa::SERVICE_IMPORTED_CONFIGS); + return false; + } + size_t matchCount = 0; + for (const auto& config : endpoint.getConfigurationTypes()) { + for (const auto& factoryConfig : factory.getSupportedConfigs()) { + if (config == factoryConfig) { + ++matchCount; + break; + } + } + } + return matchCount == factory.getSupportedConfigs().size(); +} + +bool celix::rsa::RemoteServiceAdmin::isExportServiceMatch(const celix::Properties& svcProperties, const celix::rsa::IExportServiceFactory& factory) const { + if (factory.getSupportedIntents().empty()) { + L_WARN("Matching service marked for export with a export service factory with no supported intents, this will always fail"); + return false; + } + auto providedIntents = celix::split(svcProperties.get(celix::rsa::SERVICE_EXPORTED_INTENTS, "osgi.basic")); + for (const auto& intent: providedIntents) { + for (const auto& factoryIntent: factory.getSupportedIntents()) { + if (intent == factoryIntent) { + return true; + } + } + } + return false; +} + void celix::rsa::RemoteServiceAdmin::createImportServices() { - auto it = _toBeImportedServices.begin(); - while (it != _toBeImportedServices.end()) { + //precondition mutex taken + auto it = toBeImportedServices.begin(); + while (it != toBeImportedServices.end()) { auto interface = (*it)->getInterface(); - 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; + bool match = false; + for (auto factoryIt = importServiceFactories.lower_bound(interface); factoryIt != importServiceFactories.end() && factoryIt->first == interface; ++factoryIt) { + if (isEndpointMatch(**it, *factoryIt->second)) { + match = true; + auto endpointId = (*it)->getId(); + L_DEBUG("Adding endpoint %s, created export service for %s", endpointId.c_str(), (*it)->getInterface().c_str()); + importedServices.emplace(endpointId, factoryIt->second->importService(**it)); + break; + } else { + L_TRACE("Config mismatch."); + } + } + if (match) { + it = toBeImportedServices.erase(it); + } else { + L_DEBUG("Adding endpoint to be imported but no matching factory available yet, delaying import"); + ++it; } - auto endpointId = (*it)->getId(); - L_DEBUG("Adding endpoint, created service"); - _importedServices.emplace(endpointId, existingFactory->second->importService(**it)); - it = _toBeImportedServices.erase(it); } } void celix::rsa::RemoteServiceAdmin::createExportServices() { - auto it = _toBeExportedServices.begin(); - while (it != _toBeExportedServices.end()) { + //precondition mutex taken + 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); - it++; - continue; + bool match = false; + for (auto factoryIt = exportServiceFactories.lower_bound(serviceName); factoryIt != exportServiceFactories.end() && factoryIt->first == serviceName; ++factoryIt) { + if (isExportServiceMatch(svcProperties, *factoryIt->second)) { + match = true; + exportedServices.emplace(svcId, factoryIt->second->exportService(svcProperties)); + break; + } else { + L_TRACE("Intent mismatch"); + } } - 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; + if (match) { + it = toBeExportedServices.erase(it); + } else { + L_DEBUG("Adding endpoint to be imported but no matching factory available yet, delaying import"); + ++it; } - _exportedServices.emplace(svcId, factory->second->exportService(svcProperties)); - it = _toBeExportedServices.erase(it); } -} - -class AdminActivator { -public: - explicit AdminActivator(const std::shared_ptr<celix::BundleContext>& ctx) { - auto admin = std::make_shared<celix::rsa::RemoteServiceAdmin>(celix::LogHelper{ctx, celix::typeName<celix::rsa::RemoteServiceAdmin>()}); - - auto& cmp = ctx->getDependencyManager()->createComponent(admin); - cmp.createServiceDependency<celix::rsa::EndpointDescription>() - .setRequired(false) - .setStrategy(celix::dm::DependencyUpdateStrategy::locking) - .setCallbacks(&celix::rsa::RemoteServiceAdmin::addEndpoint, &celix::rsa::RemoteServiceAdmin::removeEndpoint); - cmp.createServiceDependency<celix::rsa::IImportServiceFactory>() - .setRequired(false) - .setStrategy(celix::dm::DependencyUpdateStrategy::locking) - .setCallbacks(&celix::rsa::RemoteServiceAdmin::addImportedServiceFactory, &celix::rsa::RemoteServiceAdmin::removeImportedServiceFactory); - cmp.createServiceDependency<celix::rsa::IExportServiceFactory>() - .setRequired(false) - .setStrategy(celix::dm::DependencyUpdateStrategy::locking) - .setCallbacks(&celix::rsa::RemoteServiceAdmin::addExportedServiceFactory, &celix::rsa::RemoteServiceAdmin::removeExportedServiceFactory); - cmp.build(); - - //note adding void service dependencies is not supported for the dependency manager, using a service tracker instead. - _remoteServiceTracker = ctx->trackAnyServices() - .setFilter(std::string{"("}.append(celix::rsa::SERVICE_EXPORTED_INTERFACES).append("=*)")) - .addAddWithPropertiesCallback([admin](const std::shared_ptr<void>& svc, const std::shared_ptr<const celix::Properties>& properties) { - admin->addService(svc, properties); - }) - .addRemWithPropertiesCallback([admin](const std::shared_ptr<void>& svc, const std::shared_ptr<const celix::Properties>& properties) { - admin->removeService(svc, properties); - }) - .build(); - } -private: - std::shared_ptr<celix::ServiceTracker<void>> _remoteServiceTracker{}; -}; - -CELIX_GEN_CXX_BUNDLE_ACTIVATOR(AdminActivator) \ No newline at end of file +} \ No newline at end of file diff --git a/bundles/cxx_remote_services/admin/include/RemoteServiceAdmin.h b/bundles/cxx_remote_services/admin/src/RemoteServiceAdmin.h similarity index 63% rename from bundles/cxx_remote_services/admin/include/RemoteServiceAdmin.h rename to bundles/cxx_remote_services/admin/src/RemoteServiceAdmin.h index 969a095..408bac7 100644 --- a/bundles/cxx_remote_services/admin/include/RemoteServiceAdmin.h +++ b/bundles/cxx_remote_services/admin/src/RemoteServiceAdmin.h @@ -17,7 +17,6 @@ * under the License. */ - #include <mutex> #include "celix/LogHelper.h" @@ -35,6 +34,15 @@ namespace celix::rsa { + /** + * @brief Remote Service Admin based on endpoint/proxy factories. + * + * A Remote Service Admin which does not contain on itself any technology, but relies on remote + * service endpoint/proxy factories to create exported/imported remote services. + * + * The RSA can be configured to use different remote service endpoint/proxy factories based on the + * intent of the remote service endpoint/proxy factories. + */ class RemoteServiceAdmin { public: explicit RemoteServiceAdmin(celix::LogHelper logHelper); @@ -57,24 +65,26 @@ namespace celix::rsa { private: void createExportServices(); void createImportServices(); + bool isEndpointMatch(const celix::rsa::EndpointDescription& endpoint, const celix::rsa::IImportServiceFactory& factory) const; + bool isExportServiceMatch(const celix::Properties& svcProperties, const celix::rsa::IExportServiceFactory& factory) const; - celix::LogHelper _logHelper; - std::mutex _m{}; // protects below + celix::LogHelper logHelper; + std::mutex mutex{}; // protects below #if __cpp_lib_memory_resource - std::pmr::unsynchronized_pool_resource _memResource{}; + std::pmr::unsynchronized_pool_resource memResource{}; - 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::IImportServiceGuard>> _importedServices{&_memResource}; //key = endpoint id - std::pmr::unordered_map<long, std::unique_ptr<celix::rsa::IExportServiceGuard>> _exportedServices{&_memResource}; //key = service id + std::pmr::multimap<std::string, std::shared_ptr<celix::rsa::IExportServiceFactory>> exportServiceFactories{&memResource}; //key = service name + std::pmr::multimap<std::string, std::shared_ptr<celix::rsa::IImportServiceFactory>> importServiceFactories{&memResource}; //key = service name + std::pmr::unordered_map<std::string, std::unique_ptr<celix::rsa::IImportRegistration>> importedServices{&memResource}; //key = endpoint id + std::pmr::unordered_map<long, std::unique_ptr<celix::rsa::IExportRegistration>> exportedServices{&memResource}; //key = service id #else - 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::IImportServiceGuard>> _importedServices{}; //key = endpoint id - std::unordered_map<long, std::unique_ptr<celix::rsa::IExportServiceGuard>> _exportedServices{}; //key = service id + std::multimap<std::string, std::shared_ptr<celix::rsa::IExportServiceFactory>> exportServiceFactories{}; //key = service name + std::multimap<std::string, std::shared_ptr<celix::rsa::IImportServiceFactory>> importServiceFactories{}; //key = service name + std::unordered_map<std::string, std::unique_ptr<celix::rsa::IImportServiceGuard>> importedServices{}; //key = endpoint id + std::unordered_map<long, std::unique_ptr<celix::rsa::IExportServiceGuard>> exportedServices{}; //key = service id #endif - std::vector<std::shared_ptr<celix::rsa::EndpointDescription>> _toBeImportedServices{}; - std::vector<std::shared_ptr<const celix::Properties>> _toBeExportedServices{}; + std::vector<std::shared_ptr<celix::rsa::EndpointDescription>> toBeImportedServices{}; + std::vector<std::shared_ptr<const celix::Properties>> toBeExportedServices{}; }; } \ No newline at end of file diff --git a/bundles/cxx_remote_services/admin/src/RemoteServiceAdminActivator.cc b/bundles/cxx_remote_services/admin/src/RemoteServiceAdminActivator.cc new file mode 100644 index 0000000..0b646ac --- /dev/null +++ b/bundles/cxx_remote_services/admin/src/RemoteServiceAdminActivator.cc @@ -0,0 +1,63 @@ +/* + * 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 "RemoteServiceAdmin.h" + +/** + * @Brief Remote Service Admin which use export/import service factories to import/export remote services. + * + * Supported intends and config are based on what is supported by the export/import service factories. + */ +class AdminActivator { +public: + explicit AdminActivator(const std::shared_ptr<celix::BundleContext>& ctx) { + auto admin = std::make_shared<celix::rsa::RemoteServiceAdmin>(celix::LogHelper{ctx, celix::typeName<celix::rsa::RemoteServiceAdmin>()}); + + auto& cmp = ctx->getDependencyManager()->createComponent(admin); + cmp.createServiceDependency<celix::rsa::EndpointDescription>() + .setRequired(false) + .setStrategy(celix::dm::DependencyUpdateStrategy::locking) + .setCallbacks(&celix::rsa::RemoteServiceAdmin::addEndpoint, &celix::rsa::RemoteServiceAdmin::removeEndpoint); + cmp.createServiceDependency<celix::rsa::IImportServiceFactory>() + .setRequired(false) + .setStrategy(celix::dm::DependencyUpdateStrategy::locking) + .setCallbacks(&celix::rsa::RemoteServiceAdmin::addImportedServiceFactory, &celix::rsa::RemoteServiceAdmin::removeImportedServiceFactory); + cmp.createServiceDependency<celix::rsa::IExportServiceFactory>() + .setRequired(false) + .setStrategy(celix::dm::DependencyUpdateStrategy::locking) + .setCallbacks(&celix::rsa::RemoteServiceAdmin::addExportedServiceFactory, &celix::rsa::RemoteServiceAdmin::removeExportedServiceFactory); + cmp.build(); + + //note adding void service dependencies is not supported for the dependency manager, using a service tracker instead. + _remoteServiceTracker = ctx->trackAnyServices() + .setFilter(std::string{"("}.append(celix::rsa::SERVICE_EXPORTED_INTERFACES).append("=*)")) + .addAddWithPropertiesCallback([admin](const std::shared_ptr<void>& svc, const std::shared_ptr<const celix::Properties>& properties) { + admin->addService(svc, properties); + }) + .addRemWithPropertiesCallback([admin](const std::shared_ptr<void>& svc, const std::shared_ptr<const celix::Properties>& properties) { + admin->removeService(svc, properties); + }) + .build(); + } +private: + std::shared_ptr<celix::ServiceTracker<void>> _remoteServiceTracker{}; +}; + +CELIX_GEN_CXX_BUNDLE_ACTIVATOR(AdminActivator) \ No newline at end of file diff --git a/bundles/cxx_remote_services/discovery_configured/gtest/src/RsaConfiguredDiscoveryTestSuite.cc b/bundles/cxx_remote_services/discovery_configured/gtest/src/RsaConfiguredDiscoveryTestSuite.cc index dcd900f..cd773be 100644 --- a/bundles/cxx_remote_services/discovery_configured/gtest/src/RsaConfiguredDiscoveryTestSuite.cc +++ b/bundles/cxx_remote_services/discovery_configured/gtest/src/RsaConfiguredDiscoveryTestSuite.cc @@ -54,7 +54,7 @@ TEST_F(RsaConfiguredDiscoveryTestSuite, discoverConfiguredEndpoints) { auto count = ctx->useServices<celix::rsa::EndpointDescription>() .addUseCallback([](auto& endpoint) { EXPECT_NE(endpoint.getId(), ""); - EXPECT_NE(endpoint.getConfigurationTypes(), ""); + EXPECT_NE(endpoint.getConfigurationTypes(), std::vector<std::string>{}); EXPECT_NE(endpoint.getInterface(), ""); EXPECT_NE(endpoint.getFrameworkUUID(), ""); EXPECT_NE(endpoint.getProperties().get("endpoint.scope"), ""); //note async specific diff --git a/bundles/cxx_remote_services/integration/src/CalculatorProvider.cc b/bundles/cxx_remote_services/integration/src/CalculatorProvider.cc index dd4a3a2..ec4ea86 100644 --- a/bundles/cxx_remote_services/integration/src/CalculatorProvider.cc +++ b/bundles/cxx_remote_services/integration/src/CalculatorProvider.cc @@ -50,7 +50,8 @@ public: cmp.createProvidedService<ICalculator>() .addProperty("service.exported.interfaces", celix::typeName<ICalculator>()) .addProperty("endpoint.topic", "test") - .addProperty("endpoint.scope", "default"); + .addProperty("endpoint.scope", "default") + .addProperty("service.exported.intents", "osgi.async"); cmp.build(); } }; diff --git a/bundles/cxx_remote_services/integration/src/TestExportImportRemoteServiceFactory.cc b/bundles/cxx_remote_services/integration/src/TestExportImportRemoteServiceFactory.cc index 154e42b..19e3dab 100644 --- a/bundles/cxx_remote_services/integration/src/TestExportImportRemoteServiceFactory.cc +++ b/bundles/cxx_remote_services/integration/src/TestExportImportRemoteServiceFactory.cc @@ -158,7 +158,7 @@ private: /** * A import service guard, which will remove the component if it goes out of scope. */ -class ComponentImportServiceGuard final : public celix::rsa::IImportServiceGuard { +class ComponentImportServiceGuard final : public celix::rsa::IImportRegistration { public: ComponentImportServiceGuard(std::shared_ptr<celix::BundleContext> _ctx, std::string _componentId) : ctx{std::move(_ctx)}, componentId{std::move(_componentId)} {} ~ComponentImportServiceGuard() noexcept override { @@ -177,14 +177,12 @@ private: */ class CalculatorImportServiceFactory final : public celix::rsa::IImportServiceFactory { public: - explicit CalculatorImportServiceFactory(std::shared_ptr<celix::BundleContext> _ctx) : ctx{std::move(_ctx)}, logHelper{ctx, "celix::rsa::RemoteServiceFactory"} {} + static constexpr const char * const CONFIGS = "pubsub"; - std::unique_ptr<celix::rsa::IImportServiceGuard> importService(const celix::rsa::EndpointDescription& endpoint) override { - if (endpoint.getConfigurationTypes() != "pubsub") { - ctx->logTrace("skipping endpoint, not pubsub configuration. Found config '%s'", endpoint.getConfigurationTypes().c_str()); - return nullptr; - } + explicit CalculatorImportServiceFactory(std::shared_ptr<celix::BundleContext> _ctx) : ctx{std::move(_ctx)}, logHelper{ctx, "celix::rsa::RemoteServiceFactory"} {} + ~CalculatorImportServiceFactory() noexcept override = default; + std::unique_ptr<celix::rsa::IImportRegistration> importService(const celix::rsa::EndpointDescription& endpoint) override { auto topic = endpoint.getProperties().get("endpoint.topic"); auto scope = endpoint.getProperties().get("endpoint.topic"); if (topic.empty() || scope.empty()) { @@ -195,6 +193,15 @@ public: auto componentId = createImportedCalculatorComponent(endpoint); return std::make_unique<ComponentImportServiceGuard>(ctx, std::move(componentId)); } + + [[nodiscard]] const std::string& getRemoteServiceType() const override { + return serviceType; + } + + const std::vector<std::string>& getSupportedConfigs() const override { + return configs; + } + private: std::string createImportedCalculatorComponent(const celix::rsa::EndpointDescription& endpoint) { auto invokeTopic = endpoint.getProperties().get("endpoint.topic") + "_invoke"; @@ -243,6 +250,8 @@ private: return cmp.getUUID(); } + const std::string serviceType = celix::typeName<ICalculator>(); + const std::vector<std::string> configs = celix::split(CONFIGS); std::shared_ptr<celix::BundleContext> ctx; celix::LogHelper logHelper; std::mutex mutex{}; //protects below @@ -341,7 +350,7 @@ private: /** * A import service guard, which will remove the component if it goes out of scope. */ -class ComponentExportServiceGuard final : public celix::rsa::IExportServiceGuard { +class ComponentExportServiceGuard final : public celix::rsa::IExportRegistration { public: ComponentExportServiceGuard(std::shared_ptr<celix::BundleContext> _ctx, std::string _componentId) : ctx{std::move(_ctx)}, componentId{std::move(_componentId)} {} ~ComponentExportServiceGuard() noexcept override { @@ -360,10 +369,14 @@ private: */ class CalculatorExportServiceFactory final : public celix::rsa::IExportServiceFactory { public: + static constexpr const char * const CONFIGS = "pubsub"; + static constexpr const char * const INTENTS = "osgi.async"; + explicit CalculatorExportServiceFactory(std::shared_ptr<celix::BundleContext> _ctx) : ctx{std::move(_ctx)}, logHelper{ctx, "celix::rsa::RemoteServiceFactory"} {} + ~CalculatorExportServiceFactory() noexcept override = default; - std::unique_ptr<celix::rsa::IExportServiceGuard> exportService(const celix::Properties& serviceProperties) override { + std::unique_ptr<celix::rsa::IExportRegistration> exportService(const celix::Properties& serviceProperties) override { auto topic = serviceProperties.get("endpoint.topic"); auto scope = serviceProperties.get("endpoint.topic"); if (topic.empty() || scope.empty()) { @@ -374,6 +387,19 @@ public: auto componentId = createExportedCalculatorComponent(serviceProperties); return std::make_unique<ComponentExportServiceGuard>(ctx, std::move(componentId)); } + + [[nodiscard]] const std::string& getRemoteServiceType() const override { + return serviceType; + } + + [[nodiscard]] const std::vector<std::string>& getSupportedIntents() const override { + return intents; + } + + [[nodiscard]] const std::vector<std::string>& getSupportedConfigs() const override { + return configs; + } + private: std::string createExportedCalculatorComponent(const celix::Properties& serviceProperties) { auto invokeTopic = serviceProperties.get("endpoint.topic") + "_invoke"; @@ -417,6 +443,9 @@ private: return cmp.getUUID(); } + const std::string serviceType = celix::typeName<ICalculator>(); + const std::vector<std::string> configs = celix::split(CONFIGS); + const std::vector<std::string> intents = celix::split(INTENTS); std::shared_ptr<celix::BundleContext> ctx; celix::LogHelper logHelper; std::mutex mutex{}; //protects below @@ -428,12 +457,15 @@ public: ctx->logInfo("Starting TestExportImportRemoteServiceFactory"); registrations.emplace_back( ctx->registerService<celix::rsa::IImportServiceFactory>(std::make_shared<CalculatorImportServiceFactory>(ctx)) - .addProperty(celix::rsa::IImportServiceFactory::TARGET_SERVICE_NAME, celix::typeName<ICalculator>()) + .addProperty(celix::rsa::IImportServiceFactory::REMOTE_SERVICE_TYPE, celix::typeName<ICalculator>()) + .addProperty(celix::rsa::REMOTE_CONFIGS_SUPPORTED, CalculatorImportServiceFactory::CONFIGS) .build() ); registrations.emplace_back( ctx->registerService<celix::rsa::IExportServiceFactory>(std::make_shared<CalculatorExportServiceFactory>(ctx)) - .addProperty(celix::rsa::IExportServiceFactory::TARGET_SERVICE_NAME, celix::typeName<ICalculator>()) + .addProperty(celix::rsa::IExportServiceFactory::REMOTE_SERVICE_TYPE, celix::typeName<ICalculator>()) + .addProperty(celix::rsa::REMOTE_CONFIGS_SUPPORTED, CalculatorExportServiceFactory::CONFIGS) + .addProperty(celix::rsa::REMOTE_INTENTS_SUPPORTED, CalculatorExportServiceFactory::INTENTS) .build() ); registrations.emplace_back( diff --git a/bundles/cxx_remote_services/rsa_spi/include/celix/rsa/EndpointDescription.h b/bundles/cxx_remote_services/rsa_spi/include/celix/rsa/EndpointDescription.h index 4b43142..6408c9d 100644 --- a/bundles/cxx_remote_services/rsa_spi/include/celix/rsa/EndpointDescription.h +++ b/bundles/cxx_remote_services/rsa_spi/include/celix/rsa/EndpointDescription.h @@ -21,6 +21,7 @@ #include <string> #include <map> +#include "celix/Utils.h" #include "celix/Constants.h" #include "celix/Properties.h" #include "celix/rsa/RemoteConstants.h" @@ -51,7 +52,13 @@ namespace celix::rsa { * * @param The properties from which to create the Endpoint Description. */ - explicit EndpointDescription(celix::Properties properties) : endpointProperties{std::move(properties)} { + explicit EndpointDescription(celix::Properties properties) : + endpointProperties{std::move(properties)}, + endpointId{endpointProperties.get(celix::rsa::ENDPOINT_ID)}, + configurationTypes{celix::split(endpointProperties.get(celix::rsa::SERVICE_IMPORTED_CONFIGS))}, + frameworkUUID{endpointProperties.get(celix::rsa::ENDPOINT_FRAMEWORK_UUID)}, + intents{celix::split(endpointProperties.get(celix::rsa::SERVICE_INTENTS))}, + interface{endpointProperties.get(celix::SERVICE_NAME)} { checkValidEndpoint(); } @@ -66,8 +73,13 @@ namespace celix::rsa { * @param serviceProperties The service properties of a service that can be exported. * @param rsaProperties The optional properties provided by the Remote Service Admin. */ - EndpointDescription(std::string_view frameworkUUID, const celix::Properties& serviceProperties, const celix::Properties& rsaProperties = {}) : endpointProperties{ - importedProperties(frameworkUUID, serviceProperties, rsaProperties)} { + EndpointDescription(std::string_view frameworkUUID, const celix::Properties& serviceProperties, const celix::Properties& rsaProperties = {}) : + endpointProperties{importedProperties(frameworkUUID, serviceProperties, rsaProperties)}, + endpointId{endpointProperties.get(celix::rsa::ENDPOINT_ID)}, + configurationTypes{celix::split(endpointProperties.get(celix::rsa::SERVICE_IMPORTED_CONFIGS))}, + frameworkUUID{endpointProperties.get(celix::rsa::ENDPOINT_FRAMEWORK_UUID)}, + intents{celix::split(endpointProperties.get(celix::rsa::SERVICE_INTENTS))}, + interface{endpointProperties.get(celix::SERVICE_NAME)} { checkValidEndpoint(); } @@ -79,8 +91,8 @@ namespace celix::rsa { * Two Endpoint Descriptions with the same id must represent the same endpoint. * The value of the id is stored in the RemoteConstants.ENDPOINT_ID property. */ - [[nodiscard]] std::string getId() const { - return endpointProperties.get(celix::rsa::ENDPOINT_ID); + [[nodiscard]] const std::string& getId() const { + return endpointId; } /** @@ -93,8 +105,8 @@ namespace celix::rsa { * increase the change a receiving distribution provider can create a connection to this endpoint. * This value of the configuration types is stored in the celix::rsa::SERVICE_IMPORTED_CONFIGS service property. */ - [[nodiscard]] std::string getConfigurationTypes() const { - return endpointProperties.get(celix::rsa::SERVICE_IMPORTED_CONFIGS); + [[nodiscard]] const std::vector<std::string>& getConfigurationTypes() const { + return configurationTypes; } /** @@ -102,8 +114,8 @@ namespace celix::rsa { * * The value of the remote framework UUID is stored in the celix::rsa::ENDPOINT_FRAMEWORK_UUID endpoint property. */ - [[nodiscard]] std::string getFrameworkUUID() const { - return endpointProperties.get(celix::rsa::ENDPOINT_FRAMEWORK_UUID); + [[nodiscard]] const std::string& getFrameworkUUID() const { + return frameworkUUID; } /** @@ -114,17 +126,16 @@ namespace celix::rsa { * All qualified intents must have been expanded. * This value of the intents is stored in the RemoteConstants.SERVICE_INTENTS service property. */ - //TODO make std::vector<std::string> - [[nodiscard]] std::string getIntents() const { - return endpointProperties.get(celix::rsa::SERVICE_INTENTS); + [[nodiscard]] const std::vector<std::string>& getIntents() const { + return intents; } /** * @brief Provide the interface implemented by the exported service. * The value of the interface is derived from the objectClass property. */ - [[nodiscard]] std::string getInterface() const { - return endpointProperties.get(celix::SERVICE_NAME); + [[nodiscard]] const std::string& getInterface() const { + return interface; } /** @@ -180,7 +191,12 @@ namespace celix::rsa { throw celix::rsa::RemoteServicesException{baseMsg.append(celix::SERVICE_NAME)}; } } - + const celix::Properties endpointProperties; + const std::string endpointId; + const std::vector<std::string> configurationTypes; + const std::string frameworkUUID; + const std::vector<std::string> intents; + const std::string interface; }; } // end namespace celix::rsa. diff --git a/bundles/cxx_remote_services/rsa_spi/include/celix/rsa/IExportRegistration.h b/bundles/cxx_remote_services/rsa_spi/include/celix/rsa/IExportRegistration.h new file mode 100644 index 0000000..81944c6 --- /dev/null +++ b/bundles/cxx_remote_services/rsa_spi/include/celix/rsa/IExportRegistration.h @@ -0,0 +1,31 @@ +/* + * 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 + +namespace celix::rsa { + + /** + * @brief IExportRegistration class which represent a (opaque) exported service. + * If lifetime of this object expires it should remove the underlining exported service. + * */ + class IExportRegistration { + public: + virtual ~IExportRegistration() noexcept = default; + }; +} \ No newline at end of file diff --git a/bundles/cxx_remote_services/rsa_spi/include/celix/rsa/IExportServiceFactory.h b/bundles/cxx_remote_services/rsa_spi/include/celix/rsa/IExportServiceFactory.h index 66383b6..3b8c052 100644 --- a/bundles/cxx_remote_services/rsa_spi/include/celix/rsa/IExportServiceFactory.h +++ b/bundles/cxx_remote_services/rsa_spi/include/celix/rsa/IExportServiceFactory.h @@ -19,24 +19,16 @@ #pragma once #include <memory> -#include "celix/rsa/EndpointDescription.h" -namespace celix::rsa { +#include "celix/rsa/IExportRegistration.h" - /** - * @brief IExportServiceGuard class which represent a (opaque) exported service. - * If lifetime of this object expires it should remove the underlining exported service. - * */ - class IExportServiceGuard { - public: - virtual ~IExportServiceGuard() noexcept = default; - }; +namespace celix::rsa { /** * @brief A export service factory for a specific service type. * - * The service type which this export service factory targets is provided with - * the mandatory celix::rsa::IExportServiceFactory::TARGET_SERVICE_NAME service property. + * the mandatory service properties: + * - celix::rsa::IExportServiceFactory::REMOTE_SERVICE_TYPE * */ class IExportServiceFactory { @@ -44,16 +36,34 @@ namespace celix::rsa { /** * @brief The service name for which this factory can created exported services. */ - static constexpr const char * const TARGET_SERVICE_NAME = "target.service.name"; + static constexpr const char * const REMOTE_SERVICE_TYPE = "remote.service.type"; virtual ~IExportServiceFactory() noexcept = default; /** + * @brief The service name for which this factory can export services as remote services. + * + * The value should be based on the "remote.service.type" service property of + * this import service factory. + */ + [[nodiscard]] virtual const std::string& getRemoteServiceType() const = 0; + + /** + * @Brief The supported intents for this export service factory. + */ + [[nodiscard]] virtual const std::vector<std::string>& getSupportedIntents() const = 0; + + /** + * @Brief The supported configs for this export service factory. + */ + [[nodiscard]] virtual const std::vector<std::string>& getSupportedConfigs() const = 0; + + /** * @brief Exports the service identified with svcId * @param svcId The service id of the exported service. - * @return A ExportService. + * @return A new export registration. * @throws celix::rsa::RemoteServicesException if the export failed. */ - virtual std::unique_ptr<celix::rsa::IExportServiceGuard> exportService(const celix::Properties& serviceProperties) = 0; + [[nodiscard]] virtual std::unique_ptr<celix::rsa::IExportRegistration> exportService(const celix::Properties& serviceProperties) = 0; }; } \ No newline at end of file diff --git a/bundles/cxx_remote_services/rsa_spi/include/celix/rsa/IImportRegistration.h b/bundles/cxx_remote_services/rsa_spi/include/celix/rsa/IImportRegistration.h new file mode 100644 index 0000000..cb366dc --- /dev/null +++ b/bundles/cxx_remote_services/rsa_spi/include/celix/rsa/IImportRegistration.h @@ -0,0 +1,31 @@ +/* + * 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 + +namespace celix::rsa { + + /** + * @brief IImportRegistration class which represent a (opaque) imported service. + * If lifetime of this object expires it should remove the underlining imported service. + */ + class IImportRegistration { + public: + virtual ~IImportRegistration() noexcept = default; + }; +} \ No newline at end of file diff --git a/bundles/cxx_remote_services/rsa_spi/include/celix/rsa/IImportServiceFactory.h b/bundles/cxx_remote_services/rsa_spi/include/celix/rsa/IImportServiceFactory.h index 7c6f3a1..354e866 100644 --- a/bundles/cxx_remote_services/rsa_spi/include/celix/rsa/IImportServiceFactory.h +++ b/bundles/cxx_remote_services/rsa_spi/include/celix/rsa/IImportServiceFactory.h @@ -19,41 +19,47 @@ #pragma once #include <memory> + #include "celix/rsa/EndpointDescription.h" +#include "celix/rsa/IImportRegistration.h" namespace celix::rsa { /** - * @brief IImportServiceGuard class which represent a (opaque) imported service. - * If lifetime of this object expires it should remove the underlining imported service. - */ - class IImportServiceGuard { - public: - virtual ~IImportServiceGuard() noexcept = default; - }; - - /** * @brief A import service factory for a specific service type. * - * The service type which this import service factory targets is provided with - * the mandatory celix::rsa::IImportServiceFactory::TARGET_SERVICE_NAME service property. + * The service type which this export service factory targets is provided with `REMOTE_SERVICE_TYPE` and + * the supported configs with `REMOTE_CONFIGS_SUPPORTED`. * */ class IImportServiceFactory { public: /** - * @brief The service name for which this factory can created exported services. + * @brief The service name for which this factory can import remote services. */ - static constexpr const char * const TARGET_SERVICE_NAME = "target.service.name"; + static constexpr const char * const REMOTE_SERVICE_TYPE = "remote.service.type"; virtual ~IImportServiceFactory() noexcept = default; /** + * @brief The service name for which this factory can import remote services. + * + * The value should be based on the "remote.service.type" service property of + * this import service factory. + */ + [[nodiscard]] virtual const std::string& getRemoteServiceType() const = 0; + + /** + * @Brief The supported configs for this import service factory. + */ + [[nodiscard]] virtual const std::vector<std::string>& getSupportedConfigs() const = 0; + + /** * @brief Imports the service identified with svcId * @param svcId The service id of the exported service. - * @return A ImportService. + * @return A new import registration. * @throws celix::rsa::RemoteServicesException if the import failed. */ - virtual std::unique_ptr<celix::rsa::IImportServiceGuard> importService(const celix::rsa::EndpointDescription& endpoint) = 0; + [[nodiscard]] virtual std::unique_ptr<celix::rsa::IImportRegistration> importService(const celix::rsa::EndpointDescription& endpoint) = 0; }; } \ No newline at end of file diff --git a/bundles/cxx_remote_services/rsa_spi/include/celix/rsa/RemoteConstants.h b/bundles/cxx_remote_services/rsa_spi/include/celix/rsa/RemoteConstants.h index 9dae5e3..7cae240 100644 --- a/bundles/cxx_remote_services/rsa_spi/include/celix/rsa/RemoteConstants.h +++ b/bundles/cxx_remote_services/rsa_spi/include/celix/rsa/RemoteConstants.h @@ -91,7 +91,7 @@ namespace celix::rsa { /** * @brief Service property marking the service for export. It defines the interfaces under which this service can be exported. * - * Note for Celix only 1 interface can be register per service regiration, so only 1 interface can be exported using + * Note for Celix only 1 interface can be register per service registration, so only 1 interface can be exported using * the service.exported.interfaces property. * This value must be the exported service type or the value of an asterisk ('*' \u002A). * The value of this property must be of type string. diff --git a/bundles/logging/log_helper/include/celix/LogHelper.h b/bundles/logging/log_helper/include/celix/LogHelper.h index 3f447f2..c22cb35 100644 --- a/bundles/logging/log_helper/include/celix/LogHelper.h +++ b/bundles/logging/log_helper/include/celix/LogHelper.h @@ -32,7 +32,7 @@ namespace celix { /** * @brief Logs to celix_logHelper_log using the CELIX_LOG_LEVEL_TRACE level, printf style */ - void trace(const char *format, ...) { + void trace(const char *format, ...) const { va_list args; va_start(args, format); vlog(CELIX_LOG_LEVEL_TRACE, format, args); @@ -42,7 +42,7 @@ namespace celix { /** * @brief Logs to celix_logHelper_log using the CELIX_LOG_LEVEL_DEBUG level, printf style */ - void debug(const char *format, ...) { + void debug(const char *format, ...) const { va_list args; va_start(args, format); vlog(CELIX_LOG_LEVEL_DEBUG, format, args); @@ -52,7 +52,7 @@ namespace celix { /** * @brief Logs to celix_logHelper_log using the CELIX_LOG_LEVEL_INFO level, printf style */ - void info(const char *format, ...) { + void info(const char *format, ...) const { va_list args; va_start(args, format); vlog(CELIX_LOG_LEVEL_INFO, format, args); @@ -62,7 +62,7 @@ namespace celix { /** * @brief Logs to celix_logHelper_log using the CELIX_LOG_LEVEL_WARNING level, printf style */ - void warning(const char *format, ...) { + void warning(const char *format, ...) const { va_list args; va_start(args, format); vlog(CELIX_LOG_LEVEL_WARNING, format, args); @@ -72,7 +72,7 @@ namespace celix { /** * @brief Logs to celix_logHelper_log using the CELIX_LOG_LEVEL_ERROR level, printf style */ - void error(const char *format, ...) { + void error(const char *format, ...) const { va_list args; va_start(args, format); vlog(CELIX_LOG_LEVEL_ERROR, format, args); @@ -82,7 +82,7 @@ namespace celix { /** * @brief Logs to celix_logHelper_log using the CELIX_LOG_LEVEL_FATAL level, printf style */ - void fatal(const char *format, ...) { + void fatal(const char *format, ...) const { va_list args; va_start(args, format); vlog(CELIX_LOG_LEVEL_FATAL, format, args); @@ -94,7 +94,7 @@ namespace celix { * * Silently ignores log level CELIX_LOG_LEVEL_DISABLED. */ - void vlog(celix_log_level_e level, const char *format, va_list formatArgs) { + void vlog(celix_log_level_e level, const char *format, va_list formatArgs) const { celix_logHelper_vlog(logHelper.get(), level, format, formatArgs); }
