This is an automated email from the ASF dual-hosted git repository. pnoltes pushed a commit to branch feature/async_update in repository https://gitbox.apache.org/repos/asf/celix.git
commit 270ef6415407cc7da9bffb377f28b443bbc01df9 Author: Pepijn Noltes <[email protected]> AuthorDate: Fri Apr 9 10:54:58 2021 +0200 Refactor remote service admin for update dep man and adds interfaces to rsa_spi target. --- .../async_remote_services/admin/include/admin.h | 57 ++-- bundles/async_remote_services/admin/src/admin.cc | 345 ++++++++++----------- .../common/include/ExportedServiceFactory.h | 4 +- .../include/ConfiguredDiscoveryManager.h | 10 +- .../include/ConfiguredEndpoint.h | 2 +- .../src/ConfiguredDiscoveryManagerActivator.cc | 2 +- .../discovery_configured/src/ConfiguredEndpoint.cc | 40 +-- .../examples/HardcodedExampleProvider.cc | 4 +- .../examples/HardcodedExampleSubscriber.cc | 2 +- .../rsa_spi/include/Endpoint.h | 63 ---- .../rsa_spi/include/celix/rsa/Constants.h | 28 +- .../rsa_spi/include/celix/rsa/Endpoint.h | 68 ++++ .../rsa_spi/include/celix/rsa/Exception.h | 21 ++ .../rsa/IEndpointAnnouncer.h} | 25 +- .../include/celix/rsa/IExportServiceFactory.h | 65 ++++ .../rsa_spi/include/celix/rsa/IExportedService.h | 36 +-- .../include/celix/rsa/IImportServiceFactory.h | 65 ++++ .../topology_manager/include/topology_manager.h | 6 +- .../topology_manager/src/topology_manager.cc | 8 +- libs/framework/include/celix/dm/types.h | 6 +- 20 files changed, 478 insertions(+), 379 deletions(-) diff --git a/bundles/async_remote_services/admin/include/admin.h b/bundles/async_remote_services/admin/include/admin.h index 57e043b..cf5a58a 100644 --- a/bundles/async_remote_services/admin/include/admin.h +++ b/bundles/async_remote_services/admin/include/admin.h @@ -17,13 +17,14 @@ * under the License. */ -#include <Endpoint.h> +#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>) #include <version> @@ -51,8 +52,8 @@ namespace celix::async_rsa { class AsyncAdmin { public: - explicit AsyncAdmin(std::shared_ptr<celix::dm::DependencyManager> &mng) noexcept; - ~AsyncAdmin(); + explicit AsyncAdmin(std::shared_ptr<celix::BundleContext> ctx) noexcept; + ~AsyncAdmin() noexcept = default; AsyncAdmin(AsyncAdmin const &) = delete; AsyncAdmin(AsyncAdmin&&) = delete; @@ -60,44 +61,44 @@ namespace celix::async_rsa { AsyncAdmin& operator=(AsyncAdmin&&) = delete; // Imported endpoint add/remove functions - void addEndpoint(celix::rsa::Endpoint* endpoint, Properties &&properties); - void removeEndpoint(celix::rsa::Endpoint* endpoint, Properties &&properties); + 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(celix::async_rsa::IImportedServiceFactory *factory, Properties&& properties); - void removeImportedServiceFactory(celix::async_rsa::IImportedServiceFactory *factory, Properties&& properties); + 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); // Exported endpoint add/remove functions - void addExportedServiceFactory(celix::async_rsa::IExportedServiceFactory *factory, Properties&& properties); - void removeExportedServiceFactory(celix::async_rsa::IExportedServiceFactory *factory, Properties&& properties); + 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); // Add/remove services, used to track all services registered with celix and check if remote = true. - void addService(void *svc, const celix_properties_t *props); - void removeService(void *svc, const celix_properties_t *props); - + void addService(const std::shared_ptr<void>& svc, const std::shared_ptr<const celix::Properties>& properties); + void removeService(const std::shared_ptr<void>& svc, const std::shared_ptr<const celix::Properties>& properties); + // Set logging service + void setLogger(const std::shared_ptr<celix_log_service>& logService); private: - std::shared_ptr<celix::dm::DependencyManager> _mng{}; - celix_log_helper_t *_logger; - long _serviceTrackerId{-1}; + 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, celix::async_rsa::IExportedServiceFactory*> _exportedServiceFactories{&_memResource}; - std::pmr::unordered_map<std::string, celix::async_rsa::IImportedServiceFactory*> _importedServiceFactories{&_memResource}; - std::pmr::unordered_map<std::string, celix::dm::BaseComponent&> _importedServiceInstances{&_memResource}; - std::pmr::unordered_map<std::string, celix::dm::BaseComponent&> _exportedServiceInstances{&_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. #else - std::unordered_map<std::string, celix::async_rsa::IExportedServiceFactory*> _exportedServiceFactories{}; - std::unordered_map<std::string, celix::async_rsa::IImportedServiceFactory*> _importedServiceFactories{}; - std::unordered_map<std::string, celix::dm::BaseComponent&> _importedServiceInstances{}; - std::unordered_map<std::string, celix::dm::BaseComponent&> _exportedServiceInstances{}; + 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{}; #endif - std::vector<celix::rsa::Endpoint> _toBeCreatedImportedEndpoints{}; - std::vector<std::pair<void*, Properties>> _toBeCreatedExportedEndpoints{}; - - // Internal functions for code re-use - void addEndpointInternal(celix::rsa::Endpoint& endpoint); + std::vector<std::shared_ptr<celix::rsa::Endpoint>> _toBeImportedServices{}; + std::vector<std::pair<std::shared_ptr<void>, 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 7dbc6d9..348ebcb 100644 --- a/bundles/async_remote_services/admin/src/admin.cc +++ b/bundles/async_remote_services/admin/src/admin.cc @@ -21,82 +21,80 @@ #include <celix_api.h> #include <pubsub_message_serialization_service.h> #include <ConfiguredEndpoint.h> +#include "celix/rsa/Constants.h" #define L_DEBUG(...) \ - celix_logHelper_log(_logger, CELIX_LOG_LEVEL_DEBUG, __VA_ARGS__) + if (_logService) { \ + _logService->debug(_logService->handle, __VA_ARGS__); \ + } #define L_INFO(...) \ - celix_logHelper_log(_logger, CELIX_LOG_LEVEL_INFO, __VA_ARGS__) + if (_logService) { \ + _logService->info(_logService->handle, __VA_ARGS__); \ + } #define L_WARN(...) \ - celix_logHelper_log(_logger, CELIX_LOG_LEVEL_WARNING, __VA_ARGS__) + if (_logService) { \ + _logService->warning(_logService->handle, __VA_ARGS__); \ + } #define L_ERROR(...) \ - celix_logHelper_log(_logger, CELIX_LOG_LEVEL_ERROR, __VA_ARGS__) - -celix::async_rsa::AsyncAdmin::AsyncAdmin(std::shared_ptr<celix::dm::DependencyManager> &mng) noexcept : _mng(mng), _logger(celix_logHelper_create(mng->bundleContext(), "celix_async_rsa_admin")) { - - // C++ version of tracking services without type not possible (yet?) - celix_service_tracking_options_t opts{}; - opts.callbackHandle = this; - opts.addWithProperties = [](void *handle, void *svc, const celix_properties_t *props){ - auto *admin = static_cast<AsyncAdmin*>(handle); - admin->addService(svc, props); - }; - opts.removeWithProperties = [](void *handle, void *svc, const celix_properties_t *props){ - auto *admin = static_cast<AsyncAdmin*>(handle); - admin->removeService(svc, props); - }; - _serviceTrackerId = celix_bundleContext_trackServicesWithOptions(_mng->bundleContext(), &opts); - - if(_serviceTrackerId < 0) { - L_ERROR("couldn't register tracker"); + if (_logService) { \ + _logService->error(_logService->handle, __VA_ARGS__); \ } -} -celix::async_rsa::AsyncAdmin::~AsyncAdmin() { - celix_logHelper_destroy(_logger); - celix_bundleContext_stopTracker(_mng->bundleContext(), _serviceTrackerId); +celix::async_rsa::AsyncAdmin::AsyncAdmin(std::shared_ptr<celix::BundleContext> ctx) noexcept : _ctx{std::move(ctx)} { + } -void celix::async_rsa::AsyncAdmin::addEndpoint(celix::rsa::Endpoint* endpoint, [[maybe_unused]] Properties &&properties) { +void celix::async_rsa::AsyncAdmin::addEndpoint(const std::shared_ptr<celix::rsa::Endpoint>& endpoint) { + assert(endpoint); std::unique_lock l(_m); - addEndpointInternal(*endpoint); -} -void celix::async_rsa::AsyncAdmin::removeEndpoint([[maybe_unused]] celix::rsa::Endpoint* endpoint, [[maybe_unused]] Properties &&properties) { - auto interface = properties.get(ENDPOINT_EXPORTS); + auto interface = endpoint->getExportedInterfaces(); + if (interface.empty()) { + L_WARN("Adding endpoint but missing exported interfaces"); + return; + } - if(interface.empty()) { - L_DEBUG("Removing endpoint but no exported interfaces"); + auto endpointId = endpoint->getEndpointId(); + if (endpointId.empty()) { + L_WARN("Adding endpoint but missing service id"); return; } + _toBeImportedServices.emplace_back(endpoint); - std::unique_lock l(_m); + l.unlock(); + createImportServices(); +} - _toBeCreatedImportedEndpoints.erase(std::remove_if(_toBeCreatedImportedEndpoints.begin(), _toBeCreatedImportedEndpoints.end(), [&interface](auto const &endpoint){ - auto endpointInterface = endpoint.getProperties().get(ENDPOINT_EXPORTS); - return !endpointInterface.empty() && endpointInterface == interface; - }), _toBeCreatedImportedEndpoints.end()); +void celix::async_rsa::AsyncAdmin::removeEndpoint(const std::shared_ptr<celix::rsa::Endpoint>& endpoint) { + assert(endpoint); + std::unique_lock l(_m); - auto svcId = properties.get(ENDPOINT_IDENTIFIER); + auto id = endpoint->getEndpointId(); - if(svcId.empty()) { - L_DEBUG("Removing endpoint but no service instance"); + if (id.empty()) { + L_WARN("Cannot remove endpoint without a valid id"); return; } - auto instanceIt = _importedServiceInstances.find(svcId); + _toBeImportedServices.erase(std::remove_if(_toBeImportedServices.begin(), _toBeImportedServices.end(), [&id](auto const &endpoint){ + return id == endpoint->getEndpointId(); + }), _toBeImportedServices.end()); - if(instanceIt == end(_importedServiceInstances)) { + + auto instanceIt = _importedServiceInstances.find(id); + + if (instanceIt == end(_importedServiceInstances)) { return; } - _mng->destroyComponent(instanceIt->second); + _ctx->getDependencyManager()->removeComponentAsync(instanceIt->second); _importedServiceInstances.erase(instanceIt); } -void celix::async_rsa::AsyncAdmin::addImportedServiceFactory(celix::async_rsa::IImportedServiceFactory *factory, Properties &&properties) { - auto interface = properties.get(ENDPOINT_EXPORTS); +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()) { + if (interface.empty()) { L_DEBUG("Adding service factory but no exported interfaces"); return; } @@ -112,64 +110,59 @@ void celix::async_rsa::AsyncAdmin::addImportedServiceFactory(celix::async_rsa::I _importedServiceFactories.emplace(interface, factory); - for(auto it = _toBeCreatedImportedEndpoints.begin(); it != _toBeCreatedImportedEndpoints.end();) { - auto tbceInterface = it->getProperties().get(ENDPOINT_EXPORTS); - if(tbceInterface.empty() || tbceInterface != interface) { - it++; - } else { - addEndpointInternal(*it); - _toBeCreatedImportedEndpoints.erase(it); - } - } + l.unlock(); + createImportServices(); } -void celix::async_rsa::AsyncAdmin::removeImportedServiceFactory([[maybe_unused]] celix::async_rsa::IImportedServiceFactory *factory, Properties &&properties) { - auto interface = properties.get(ENDPOINT_EXPORTS); +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()) { + if (interface.empty()) { L_WARN("Removing service factory but missing exported interfaces"); return; } std::unique_lock l(_m); _importedServiceFactories.erase(interface); -} -void celix::async_rsa::AsyncAdmin::addExportedServiceFactory(celix::async_rsa::IExportedServiceFactory *factory, Properties&& properties) { - auto interface = properties.get(ENDPOINT_EXPORTS); + //TODO TBD are the removal of the imported services also needed when a ImportedServiceFactory is removed (and maybe the bundle is uninstalled?) +} - if(interface.empty()) { - L_WARN("Adding exported factory but missing exported interfaces"); - return; +void celix::async_rsa::AsyncAdmin::createImportServices() { + std::lock_guard<std::mutex> lock{_m}; + + for (auto it = _toBeImportedServices.begin(); it != _toBeImportedServices.end(); ++it) { + auto interface = (*it)->getExportedInterfaces(); + auto existingFactory = _importedServiceFactories.find(interface); + if (existingFactory != end(_importedServiceFactories)) { + auto endpointId = (*it)->getEndpointId(); + L_DEBUG("Adding endpoint, created service"); + _importedServiceInstances.emplace(endpointId, existingFactory->second->create(endpointId).getUUID()); + _toBeImportedServices.erase(it--); + } else { + L_DEBUG("Adding endpoint to be imported but no factory available yet, delaying import"); + } } +} - std::unique_lock l(_m); - auto factoryIt = _exportedServiceFactories.find(interface); +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(factoryIt != end(_exportedServiceFactories)) { - L_WARN("Adding exported factory but factory already exists"); + if (interface.empty()) { + L_WARN("Adding exported factory but missing exported interfaces"); return; } - _exportedServiceFactories.emplace(interface, factory); - L_WARN("Looping over %i tbce for interface %s", _toBeCreatedExportedEndpoints.size(), interface.c_str()); - - for(auto it = _toBeCreatedExportedEndpoints.begin(); it != _toBeCreatedExportedEndpoints.end(); ) { - auto interfaceToBeCreated = it->second.get(ENDPOINT_EXPORTS); - L_WARN("Checking tbce interface %s", interfaceToBeCreated.c_str()); - - if(interfaceToBeCreated.empty() || interfaceToBeCreated != interface) { - it++; - } else { - auto endpointId = it->second.get(ENDPOINT_IDENTIFIER); - _exportedServiceInstances.emplace(endpointId, factory->create(it->first, endpointId)); - it = _toBeCreatedExportedEndpoints.erase(it); - } + { + std::lock_guard<std::mutex> lock{_m}; + _exportedServiceFactories.emplace(interface, factory); } + + createExportServices(); } -void celix::async_rsa::AsyncAdmin::removeExportedServiceFactory(celix::async_rsa::IExportedServiceFactory *, Properties&& properties) { - auto interface = properties.get(ENDPOINT_EXPORTS); +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"); @@ -178,143 +171,121 @@ void celix::async_rsa::AsyncAdmin::removeExportedServiceFactory(celix::async_rsa std::unique_lock l(_m); _exportedServiceFactories.erase(interface); + + //TODO TBD are the removal of the exported services also needed when a ExportedServiceFactory is removed (and maybe the bundle is uninstalled?) } -void celix::async_rsa::AsyncAdmin::addService(void *svc, const celix_properties_t *props) { - auto *objectClass = celix_properties_get(props, OSGI_FRAMEWORK_OBJECTCLASS, nullptr); - auto *remote = celix_properties_get(props, "remote", nullptr); - auto endpointId = celix_properties_get(props, ENDPOINT_IDENTIFIER, nullptr); +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"); - if(objectClass == nullptr) { + auto serviceName = props->get(celix::SERVICE_NAME, ""); + if (serviceName.empty()) { L_WARN("Adding service to be exported but missing objectclass"); return; } - if(remote == nullptr) { - // not every service is remote, this is fine but not something the RSA admin is interested in. - return; - } else { - L_WARN("found remote service %s", objectClass); - } - - if(endpointId == nullptr) { - L_WARN("Adding service to be exported but missing endpoint.id"); - return; - } - - std::unique_lock l(_m); - auto factory = _exportedServiceFactories.find(objectClass); - - if(factory == end(_exportedServiceFactories)) { - L_WARN("Adding service to be exported but no factory available yet, delaying creation"); - - Properties cppProps; - - auto it = celix_propertiesIterator_construct(props); - const char* key; - while(key = celix_propertiesIterator_nextKey(&it), key != nullptr) { - cppProps.set(key, celix_properties_get(props, key, nullptr)); - } - - _toBeCreatedExportedEndpoints.emplace_back(std::make_pair(svc, std::move(cppProps))); - return; + { + std::lock_guard<std::mutex> lock{_m}; + _toBeExportedServices.emplace_back(std::make_pair(std::move(svc), std::move(props))); } - _exportedServiceInstances.emplace(endpointId, factory->second->create(svc, endpointId)); + createExportServices(); } -void celix::async_rsa::AsyncAdmin::removeService(void *, const celix_properties_t *props) { - auto *objectClass = celix_properties_get(props, OSGI_FRAMEWORK_OBJECTCLASS, nullptr); - auto *remote = celix_properties_get(props, "remote", nullptr); - auto svcId = celix_properties_get(props, ENDPOINT_IDENTIFIER, nullptr); - - if(objectClass == nullptr) { - L_WARN("Removing service to be exported but missing objectclass"); - return; - } - - if(remote == nullptr) { - // not every service is remote, this is fine but not something the RSA admin is interested in. - return; - } +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"); - if(svcId == nullptr) { - L_WARN("Removing service to be exported but missing endpoint.id"); + long svcId = props->getAsLong(celix::SERVICE_ID, -1); + if (svcId < 0) { + L_WARN("Removing service to be exported but missing service.id"); return; } std::unique_lock l(_m); - auto instanceIt = _exportedServiceInstances.find(svcId); - if(instanceIt == end(_exportedServiceInstances)) { - return; + //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); } - _mng->destroyComponent(instanceIt->second); - _exportedServiceInstances.erase(instanceIt); -} - -void celix::async_rsa::AsyncAdmin::addEndpointInternal(celix::rsa::Endpoint& endpoint) { - - const auto& properties = endpoint.getProperties(); - auto interface = properties.get(ENDPOINT_EXPORTS); - - if(interface.empty()) { - L_WARN("Adding endpoint but missing exported interfaces"); - return; + //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; + } } - auto endpointId = properties.get(ENDPOINT_IDENTIFIER); - - if(endpointId.empty()) { - L_WARN("Adding endpoint but missing service id"); - return; - } +} - auto existingFactory = _importedServiceFactories.find(interface); +void celix::async_rsa::AsyncAdmin::createExportServices() { + std::lock_guard<std::mutex> lock{_m}; - if(existingFactory == end(_importedServiceFactories)) { - L_DEBUG("Adding endpoint but no factory available yet, delaying creation"); - _toBeCreatedImportedEndpoints.emplace_back(celix::rsa::Endpoint{properties}); - return; + 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); + if (serviceName.empty()) { + L_WARN("Adding service to be exported but missing objectclass for svc id %li", svcId); + } else { + auto factory = _exportedServiceFactories.find(serviceName); + if (factory != _exportedServiceFactories.end()) { + 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)); + _toBeExportedServices.erase(it--); + } else { + L_DEBUG("Adding service to be exported but no factory available yet, delaying creation"); + } + } } +} - L_DEBUG("Adding endpoint, created service"); - _importedServiceInstances.emplace(endpointId, existingFactory->second->create(endpointId)); +void celix::async_rsa::AsyncAdmin::setLogger(const std::shared_ptr<celix_log_service>& logService) { + _logService = logService; } class AdminActivator { public: - explicit AdminActivator(std::shared_ptr<celix::dm::DependencyManager> mng) : - _cmp(mng->createComponent(std::make_unique<celix::async_rsa::AsyncAdmin>(mng))), _mng(std::move(mng)) { + explicit AdminActivator(const std::shared_ptr<celix::BundleContext>& ctx) { + auto admin = std::make_shared<celix::async_rsa::AsyncAdmin>(ctx); - _cmp.createServiceDependency<celix::rsa::Endpoint>() + auto& cmp = ctx->getDependencyManager()->createComponent(admin); + cmp.createServiceDependency<celix::rsa::Endpoint>() .setRequired(false) - .setCallbacks(&celix::async_rsa::AsyncAdmin::addEndpoint, &celix::async_rsa::AsyncAdmin::removeEndpoint) - .build(); - - _cmp.createServiceDependency<celix::async_rsa::IImportedServiceFactory>() + .setStrategy(celix::dm::DependencyUpdateStrategy::locking) + .setCallbacks(&celix::async_rsa::AsyncAdmin::addEndpoint, &celix::async_rsa::AsyncAdmin::removeEndpoint); + cmp.createServiceDependency<celix::async_rsa::IImportedServiceFactory>() .setRequired(false) - .setCallbacks(&celix::async_rsa::AsyncAdmin::addImportedServiceFactory, &celix::async_rsa::AsyncAdmin::removeImportedServiceFactory) - .build(); - - _cmp.createServiceDependency<celix::async_rsa::IExportedServiceFactory>() + .setStrategy(celix::dm::DependencyUpdateStrategy::locking) + .setCallbacks(&celix::async_rsa::AsyncAdmin::addImportedServiceFactory, &celix::async_rsa::AsyncAdmin::removeImportedServiceFactory); + cmp.createServiceDependency<celix::async_rsa::IExportedServiceFactory>() .setRequired(false) - .setCallbacks(&celix::async_rsa::AsyncAdmin::addExportedServiceFactory, &celix::async_rsa::AsyncAdmin::removeExportedServiceFactory) + .setStrategy(celix::dm::DependencyUpdateStrategy::locking) + .setCallbacks(&celix::async_rsa::AsyncAdmin::addExportedServiceFactory, &celix::async_rsa::AsyncAdmin::removeExportedServiceFactory); + cmp.createServiceDependency<celix_log_service>(CELIX_LOG_SERVICE_NAME) + .setRequired(false) + .setFilter(std::string{"("}.append(CELIX_LOG_SERVICE_PROPERTY_NAME).append("=celix::rsa::RemoteServiceAdmin)")) + .setStrategy(celix::dm::DependencyUpdateStrategy::suspend) + .setCallbacks(&celix::async_rsa::AsyncAdmin::setLogger); + 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("=*)")) + .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(); - - _cmp.build(); } - - ~AdminActivator() noexcept { - _mng->destroyComponent(_cmp); - } - - AdminActivator(const AdminActivator &) = delete; - AdminActivator &operator=(const AdminActivator &) = delete; private: - celix::dm::Component<celix::async_rsa::AsyncAdmin>& _cmp; - std::shared_ptr<celix::dm::DependencyManager> _mng; + std::shared_ptr<celix::ServiceTracker<void>> _remoteServiceTracker{}; }; -CELIX_GEN_CXX_BUNDLE_ACTIVATOR(AdminActivator) +CELIX_GEN_CXX_BUNDLE_ACTIVATOR(AdminActivator) \ No newline at end of file diff --git a/bundles/async_remote_services/common/include/ExportedServiceFactory.h b/bundles/async_remote_services/common/include/ExportedServiceFactory.h index 258916f..6dcc0c9 100644 --- a/bundles/async_remote_services/common/include/ExportedServiceFactory.h +++ b/bundles/async_remote_services/common/include/ExportedServiceFactory.h @@ -21,7 +21,7 @@ #include <celix/dm/DependencyManager.h> #include <pubsub_endpoint.h> #include <IExportedService.h> -#include <Endpoint.h> +#include "celix/rsa/Endpoint.h" namespace celix::async_rsa { /// Service factory interface. @@ -59,7 +59,7 @@ namespace celix::async_rsa { std::cout << "[DefaultExportedServiceFactory::create]" << std::endl; auto &cmp = _mng->template createComponent<WrapperT>(std::make_unique<WrapperT>(static_cast<SvcInterfaceT*>(svc)), std::string{WrapperT::NAME}) - .template addInterface<celix::async_rsa::IExportedService>(std::string{SvcInterfaceT::VERSION}, Properties{{ENDPOINT_EXPORTS, std::string{SvcInterfaceT::NAME}}, {ENDPOINT_IMPORTED, "false"}, {ENDPOINT_IDENTIFIER, endpointId}}); + .template addInterface<celix::async_rsa::IExportedService>(std::string{SvcInterfaceT::VERSION}, Properties{{celix::rsa::Endpoint::EXPORTS, std::string{SvcInterfaceT::NAME}}, {celix::rsa::Endpoint::IMPORTED, "false"}, {celix::rsa::Endpoint::IDENTIFIER, endpointId}}); cmp.template createCServiceDependency<pubsub_publisher_t>(PUBSUB_PUBLISHER_SERVICE_NAME) .setVersionRange("[3.0.0,4)") diff --git a/bundles/async_remote_services/discovery_configured/include/ConfiguredDiscoveryManager.h b/bundles/async_remote_services/discovery_configured/include/ConfiguredDiscoveryManager.h index 58c8a2f..f4646c6 100644 --- a/bundles/async_remote_services/discovery_configured/include/ConfiguredDiscoveryManager.h +++ b/bundles/async_remote_services/discovery_configured/include/ConfiguredDiscoveryManager.h @@ -18,13 +18,13 @@ */ #pragma once -#include <EndpointAnnouncer.h> +#include "celix/rsa/IEndpointAnnouncer.h" #include <memory> #include <vector> #include <string> -#include <Endpoint.h> +#include "celix/rsa/Endpoint.h" #include <celix_api.h> #include <ConfiguredEndpoint.h> @@ -42,7 +42,7 @@ namespace celix::rsa { * a local configuration JSON file. * This configured discovery manager announces local exported endpoints and imported endpoints from the JSON file. */ -class ConfiguredDiscoveryManager final : public EndpointAnnouncer { +class ConfiguredDiscoveryManager final : public IEndpointAnnouncer { public: /** @@ -71,6 +71,10 @@ public: */ ConfiguredDiscoveryManager& operator=(const ConfiguredDiscoveryManager&) = delete; + void announceEndpoint(std::unique_ptr<Endpoint> /*endpoint*/) override {/*nop*/} + + void revokeEndpoint(std::unique_ptr<Endpoint> /*endpoint*/) override {/*nop*/} + private: void discoverEndpoints(); diff --git a/bundles/async_remote_services/discovery_configured/include/ConfiguredEndpoint.h b/bundles/async_remote_services/discovery_configured/include/ConfiguredEndpoint.h index 9ae110f..a107397 100644 --- a/bundles/async_remote_services/discovery_configured/include/ConfiguredEndpoint.h +++ b/bundles/async_remote_services/discovery_configured/include/ConfiguredEndpoint.h @@ -18,7 +18,7 @@ */ #pragma once -#include <Endpoint.h> +#include "celix/rsa/Endpoint.h" #include <ConfiguredEndpointProperties.h> #include <optional> diff --git a/bundles/async_remote_services/discovery_configured/src/ConfiguredDiscoveryManagerActivator.cc b/bundles/async_remote_services/discovery_configured/src/ConfiguredDiscoveryManagerActivator.cc index 4beba4d..e5758f6 100644 --- a/bundles/async_remote_services/discovery_configured/src/ConfiguredDiscoveryManagerActivator.cc +++ b/bundles/async_remote_services/discovery_configured/src/ConfiguredDiscoveryManagerActivator.cc @@ -26,7 +26,7 @@ ConfiguredDiscoveryManagerActivator::ConfiguredDiscoveryManagerActivator( const std::shared_ptr<celix::dm::DependencyManager>& dependencyManager) : _component{dependencyManager->createComponent( std::make_unique<celix::rsa::ConfiguredDiscoveryManager>(dependencyManager)) - .addInterface<celix::rsa::EndpointAnnouncer>().build()}, _mng(dependencyManager) { + .addInterface<celix::rsa::IEndpointAnnouncer>().build()}, _mng(dependencyManager) { } ConfiguredDiscoveryManagerActivator::~ConfiguredDiscoveryManagerActivator() { diff --git a/bundles/async_remote_services/discovery_configured/src/ConfiguredEndpoint.cc b/bundles/async_remote_services/discovery_configured/src/ConfiguredEndpoint.cc index 4327b3f..0ded5c1 100644 --- a/bundles/async_remote_services/discovery_configured/src/ConfiguredEndpoint.cc +++ b/bundles/async_remote_services/discovery_configured/src/ConfiguredEndpoint.cc @@ -23,16 +23,16 @@ namespace celix::rsa { celix::dm::Properties convertEndpointPropertiesToCelix(const ConfiguredEndpointProperties& endpointProperties) { - return celix::dm::Properties{{ENDPOINT_IMPORTED, std::to_string(endpointProperties.isImported()).c_str()}, - {ENDPOINT_EXPORTS, endpointProperties.getExports()}, - {ENDPOINT_IDENTIFIER, endpointProperties.getId()}}; + return celix::dm::Properties{{celix::rsa::Endpoint::IMPORTED, std::to_string(endpointProperties.isImported()).c_str()}, + {celix::rsa::Endpoint::EXPORTS, endpointProperties.getExports()}, + {celix::rsa::Endpoint::IDENTIFIER, endpointProperties.getId()}}; } ConfiguredEndpointProperties convertCelixPropertiesToEndpoint(const celix::dm::Properties& celixProperties) { - auto endpointId = celixProperties.get(ENDPOINT_IDENTIFIER); - auto exports = celixProperties.get(ENDPOINT_EXPORTS); - auto imported = celixProperties.get(ENDPOINT_IMPORTED); + auto endpointId = celixProperties.get(celix::rsa::Endpoint::IDENTIFIER); + auto exports = celixProperties.get(celix::rsa::Endpoint::EXPORTS); + auto imported = celixProperties.get(celix::rsa::Endpoint::IMPORTED); return ConfiguredEndpointProperties{endpointId, (imported == "true"), {}, exports, {}, "", ""}; @@ -40,13 +40,13 @@ ConfiguredEndpointProperties convertCelixPropertiesToEndpoint(const celix::dm::P bool isValidEndpointJson(const rapidjson::Value& endpointJson) { - return (endpointJson.HasMember(ENDPOINT_IDENTIFIER) - && endpointJson.HasMember(ENDPOINT_IMPORTED) - && endpointJson.HasMember(ENDPOINT_IMPORT_CONFIGS) - && endpointJson.HasMember(ENDPOINT_EXPORTS) - && endpointJson.HasMember(ENDPOINT_OBJECTCLASS) - && endpointJson.HasMember(ENDPOINT_SCOPE) - && endpointJson.HasMember(ENDPOINT_TOPIC)); + return (endpointJson.HasMember(celix::rsa::Endpoint::IDENTIFIER) + && endpointJson.HasMember(celix::rsa::Endpoint::IMPORTED) + && endpointJson.HasMember(celix::rsa::Endpoint::IMPORT_CONFIGS) + && endpointJson.HasMember(celix::rsa::Endpoint::EXPORTS) + && endpointJson.HasMember(celix::rsa::Endpoint::OBJECTCLASS) + && endpointJson.HasMember(celix::rsa::Endpoint::SCOPE) + && endpointJson.HasMember(celix::rsa::Endpoint::TOPIC)); } std::vector<std::string> parseJSONStringArray(const rapidjson::Value& jsonArray) { @@ -69,13 +69,13 @@ ConfiguredEndpoint::ConfiguredEndpoint(const rapidjson::Value& endpointJson) : if (isValidEndpointJson(endpointJson)) { - _configuredProperties = {endpointJson[ENDPOINT_IDENTIFIER].GetString(), - endpointJson[ENDPOINT_IMPORTED].GetBool(), - parseJSONStringArray(endpointJson[ENDPOINT_IMPORT_CONFIGS]), - endpointJson[ENDPOINT_EXPORTS].GetString(), - parseJSONStringArray(endpointJson[ENDPOINT_OBJECTCLASS]), - endpointJson[ENDPOINT_SCOPE].GetString(), - endpointJson[ENDPOINT_TOPIC].GetString()}; + _configuredProperties = {endpointJson[celix::rsa::Endpoint::IDENTIFIER].GetString(), + endpointJson[celix::rsa::Endpoint::IMPORTED].GetBool(), + parseJSONStringArray(endpointJson[celix::rsa::Endpoint::IMPORT_CONFIGS]), + endpointJson[celix::rsa::Endpoint::EXPORTS].GetString(), + parseJSONStringArray(endpointJson[celix::rsa::Endpoint::OBJECTCLASS]), + endpointJson[celix::rsa::Endpoint::SCOPE].GetString(), + endpointJson[celix::rsa::Endpoint::TOPIC].GetString()}; _celixProperties = convertEndpointPropertiesToCelix(*_configuredProperties); } diff --git a/bundles/async_remote_services/examples/HardcodedExampleProvider.cc b/bundles/async_remote_services/examples/HardcodedExampleProvider.cc index f517ca1..4cbbc11 100644 --- a/bundles/async_remote_services/examples/HardcodedExampleProvider.cc +++ b/bundles/async_remote_services/examples/HardcodedExampleProvider.cc @@ -122,9 +122,9 @@ public: _subtractArgsSerializer.emplace(mng); _toStringSerializer.emplace(mng); - mng->createComponent<HardcodedService>().addInterfaceWithName<IHardcodedService>(std::string{IHardcodedService::NAME}, std::string{IHardcodedService::VERSION}, Properties{{"remote", "true"}, {ENDPOINT_IDENTIFIER, "id-01"}, {ENDPOINT_EXPORTS, "IHardcodedService"}}).build(); + mng->createComponent<HardcodedService>().addInterfaceWithName<IHardcodedService>(std::string{IHardcodedService::NAME}, std::string{IHardcodedService::VERSION}, Properties{{"remote", "true"}, {celix::rsa::Endpoint::IDENTIFIER, "id-01"}, {celix::rsa::Endpoint::EXPORTS, "IHardcodedService"}}).build(); auto& factory = mng->createComponent(std::make_unique<celix::async_rsa::DefaultExportedServiceFactory<IHardcodedService, ExportedHardcodedService>>(mng)) - .addInterface<celix::async_rsa::IExportedServiceFactory>("1.0.0", Properties{{ENDPOINT_EXPORTS, "IHardcodedService"}}).build(); + .addInterface<celix::async_rsa::IExportedServiceFactory>("1.0.0", Properties{{celix::rsa::Endpoint::EXPORTS, "IHardcodedService"}}).build(); _factory = &factory; } diff --git a/bundles/async_remote_services/examples/HardcodedExampleSubscriber.cc b/bundles/async_remote_services/examples/HardcodedExampleSubscriber.cc index c10f7b8..da96839 100644 --- a/bundles/async_remote_services/examples/HardcodedExampleSubscriber.cc +++ b/bundles/async_remote_services/examples/HardcodedExampleSubscriber.cc @@ -179,7 +179,7 @@ public: _toStringSerializer.emplace(mng); auto& factory = mng->createComponent(std::make_unique<celix::async_rsa::DefaultImportedServiceFactory<IHardcodedService, ImportedHardcodedService>>(mng)) - .addInterface<celix::async_rsa::IImportedServiceFactory>("1.0.0", Properties{{ENDPOINT_EXPORTS, "IHardcodedService"}}).build(); + .addInterface<celix::async_rsa::IImportedServiceFactory>("1.0.0", Properties{{celix::rsa::Endpoint::EXPORTS, "IHardcodedService"}}).build(); _factory = &factory; auto &usingCmp = mng->createComponent<UsingHardcodedServiceService>() diff --git a/bundles/async_remote_services/rsa_spi/include/Endpoint.h b/bundles/async_remote_services/rsa_spi/include/Endpoint.h deleted file mode 100644 index 76a9f47..0000000 --- a/bundles/async_remote_services/rsa_spi/include/Endpoint.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -#pragma once - -#include <string> -#include <map> - -#include <celix/dm/Properties.h> - -constexpr const char* ENDPOINT_IDENTIFIER = "endpoint.id"; -constexpr const char* ENDPOINT_IMPORTED = "service.imported"; -constexpr const char* ENDPOINT_IMPORT_CONFIGS = "service.imported.configs"; -constexpr const char* ENDPOINT_EXPORTS = "service.exported.interfaces"; -constexpr const char* ENDPOINT_OBJECTCLASS = "endpoint.objectClass"; -constexpr const char* ENDPOINT_SCOPE = "endpoint.scope"; -constexpr const char* ENDPOINT_TOPIC = "endpoint.topic"; - -namespace celix::rsa { - -/** - * Endpoint class for celix::rsa namespace. - * This class holds data for discovered remote services or published local services. - */ -class Endpoint { -public: - - /** - * Endpoint constructor. - * @param properties celix properties with information about this endpoint and what its documenting. - */ - explicit Endpoint(celix::dm::Properties properties) : _celixProperties{std::move(properties)} { - // TODO validate mandatory properties are set. - } - - [[nodiscard]] const celix::dm::Properties& getProperties() const { - return _celixProperties; - } - - [[nodiscard]] std::string getEndpointId() const { - return _celixProperties.get("endpoint.id"); - } - -protected: - celix::dm::Properties _celixProperties; - -}; -} // end namespace celix::rsa. diff --git a/libs/framework/include/celix/dm/types.h b/bundles/async_remote_services/rsa_spi/include/celix/rsa/Constants.h similarity index 63% copy from libs/framework/include/celix/dm/types.h copy to bundles/async_remote_services/rsa_spi/include/celix/rsa/Constants.h index c8fca93..2b5d0c4 100644 --- a/libs/framework/include/celix/dm/types.h +++ b/bundles/async_remote_services/rsa_spi/include/celix/rsa/Constants.h @@ -19,27 +19,13 @@ #pragma once -#include "celix/Utils.h" -namespace celix { namespace dm { - //forward declarations -// class DependencyManager; +namespace celix::rsa { - class BaseServiceDependency; + /** + * @brief Service property (named "remote") to mark a service as a remote service. + * Present means -> export service as a remote service. + */ + constexpr const char *const REMOTE_SERVICE_PROPERTY_NAME = "remote"; - class BaseProvidedService; - - template<typename T, typename I> - class ProvidedService; - - template<class T, typename I> - class CServiceDependency; - - template<class T, class I> - class ServiceDependency; - - template<typename T> - std::string typeName() { - return celix::typeName<T>(); - } -}} +} \ 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 new file mode 100644 index 0000000..97a81da --- /dev/null +++ b/bundles/async_remote_services/rsa_spi/include/celix/rsa/Endpoint.h @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +#pragma once + +#include <string> +#include <map> + +#include <celix/dm/Properties.h> + +namespace celix::rsa { + + /** + * @brief Endpoint class which represent a remote endpoint discovered by the framework. + */ + 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 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"; + + + /** + * Endpoint constructor. + * @param properties celix properties with information about this endpoint and what its documenting. + */ + explicit Endpoint(celix::Properties properties) : _celixProperties{std::move(properties)} { + // TODO validate mandatory properties are set. + } + + [[nodiscard]] const celix::dm::Properties& getProperties() const { + return _celixProperties; + } + + [[nodiscard]] std::string getEndpointId() const { + return _celixProperties.get(IDENTIFIER); + } + + [[nodiscard]] std::string getExportedInterfaces() const { + return _celixProperties.get(EXPORTS); + } + + + + protected: + celix::dm::Properties _celixProperties; + + }; +} // end namespace celix::rsa. diff --git a/bundles/async_remote_services/rsa_spi/include/celix/rsa/Exception.h b/bundles/async_remote_services/rsa_spi/include/celix/rsa/Exception.h new file mode 100644 index 0000000..058c2eb --- /dev/null +++ b/bundles/async_remote_services/rsa_spi/include/celix/rsa/Exception.h @@ -0,0 +1,21 @@ +#pragma once + +#include <exception> + +namespace celix::rsa { + + /** + * @brief Celix Remote Service Admin Exception + */ + class Exception : public std::exception { + public: + explicit Exception(std::string msg) : w{std::move(msg)} {} + + const char* what() const noexcept override { + return w.c_str(); + } + private: + const std::string w; + }; + +} \ No newline at end of file diff --git a/bundles/async_remote_services/rsa_spi/include/EndpointAnnouncer.h b/bundles/async_remote_services/rsa_spi/include/celix/rsa/IEndpointAnnouncer.h similarity index 70% rename from bundles/async_remote_services/rsa_spi/include/EndpointAnnouncer.h rename to bundles/async_remote_services/rsa_spi/include/celix/rsa/IEndpointAnnouncer.h index deebd40..425a6e4 100644 --- a/bundles/async_remote_services/rsa_spi/include/EndpointAnnouncer.h +++ b/bundles/async_remote_services/rsa_spi/include/celix/rsa/IEndpointAnnouncer.h @@ -18,45 +18,34 @@ */ #pragma once -#include <Endpoint.h> - #include <memory> -#include <celix/dm/Properties.h> +#include "celix/rsa/Endpoint.h" +#include "celix/dm/Properties.h" namespace celix::rsa { /** - * Base class defining functions for all compatible endpoint announcer classes. + * @brief Interface used to announce or revoke endpoint to the remote service discovery network/system. */ -class EndpointAnnouncer { +class IEndpointAnnouncer { public: - - /** - * Defaulted constructor. - */ - EndpointAnnouncer() = default; - /** * Defaulted virtual destructor. */ - virtual ~EndpointAnnouncer() = default; + virtual ~IEndpointAnnouncer() = default; /** * Task the endpoint announcer to make the given endpoint visible for discovery by other managers/ frameworks. * @param endpoint The endpoint pointer in question, with valid properties within. */ - virtual void announceEndpoint([[maybe_unused]] std::unique_ptr<Endpoint> endpoint) { - // default implementation ignores this function. - } + virtual void announceEndpoint(std::unique_ptr<Endpoint> endpoint) = 0; /** * Task the endpoint announcer to remove the discoverability of a given endpoint. * @param endpoint The endpoint pointer in question, with valid properties within. */ - virtual void revokeEndpoint([[maybe_unused]] std::unique_ptr<Endpoint> endpoint) { - // default implementation ignores this function. - } + virtual void revokeEndpoint(std::unique_ptr<Endpoint> endpoint) = 0; }; } // end namespace celix::rsa. 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 new file mode 100644 index 0000000..f57a3a4 --- /dev/null +++ b/bundles/async_remote_services/rsa_spi/include/celix/rsa/IExportServiceFactory.h @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +#pragma once + +#include <memory> + +namespace celix::rsa { + + /** + * @brief ExportService class which represent a (opaque) exported service. + * The lifetime of this object should be coupled with the lifetime of the exported service. + */ + class ExportedService { + 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; + }; + + /** + * @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. + * + */ + 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; + + /** + * @brief Exports the service identified with svcId + * @param svcId The service id of the exported service. + * @return A ExportService. + * @throws celix::rsa::Exception if the export failed. + */ + virtual std::unique_ptr<ExportedService> exportService(const celix::Properties& serviceProperties) = 0; + }; +} \ No newline at end of file diff --git a/libs/framework/include/celix/dm/types.h b/bundles/async_remote_services/rsa_spi/include/celix/rsa/IExportedService.h similarity index 63% copy from libs/framework/include/celix/dm/types.h copy to bundles/async_remote_services/rsa_spi/include/celix/rsa/IExportedService.h index c8fca93..50b3159 100644 --- a/libs/framework/include/celix/dm/types.h +++ b/bundles/async_remote_services/rsa_spi/include/celix/rsa/IExportedService.h @@ -16,30 +16,22 @@ * specific language governing permissions and limitations * under the License. */ - #pragma once -#include "celix/Utils.h" - -namespace celix { namespace dm { - //forward declarations -// class DependencyManager; - - class BaseServiceDependency; - - class BaseProvidedService; - - template<typename T, typename I> - class ProvidedService; +#include "celix/rsa/Endpoint.h" - template<class T, typename I> - class CServiceDependency; +namespace celix::rsa { - template<class T, class I> - class ServiceDependency; + /** + * @brief IExportedService represents an exported interface + */ + class IExportedService { + public: + virtual ~IExportedService() noexcept = default; - template<typename T> - std::string typeName() { - return celix::typeName<T>(); - } -}} + /** + * @brief the endpoint which can be used to announce this exported service to the network. + */ + virtual std::shared_ptr<celix::rsa::Endpoint> getEndpoint() = 0; + }; +} 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 new file mode 100644 index 0000000..3ef1f99 --- /dev/null +++ b/bundles/async_remote_services/rsa_spi/include/celix/rsa/IImportServiceFactory.h @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +#pragma once + +#include <memory> + +namespace celix::rsa { + + /** + * @brief ImportService class which represent a (opaque) imported service. + * The lifetime of this object should be coupled with the lifetime of the imported service. + */ + class ImportedService { + public: + virtual ~ImportedService() noexcept = default; + + /** + * @brief returns the endpoint used for this imported service. + */ + virtual const celix::rsa::Endpoint& getEndpoint() const = 0; + }; + + /** + * @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. + * + */ + 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; + + /** + * @brief Imports the service identified with svcId + * @param svcId The service id of the exported service. + * @return A ImportService. + * @throws celix::rsa::Exception if the import failed. + */ + virtual std::unique_ptr<ImportedService> importService(celix::rsa::Endpoint& endpoint) = 0; + }; +} \ No newline at end of file diff --git a/bundles/async_remote_services/topology_manager/include/topology_manager.h b/bundles/async_remote_services/topology_manager/include/topology_manager.h index fff53db..710cbdb 100644 --- a/bundles/async_remote_services/topology_manager/include/topology_manager.h +++ b/bundles/async_remote_services/topology_manager/include/topology_manager.h @@ -17,7 +17,7 @@ * under the License. */ -#include <EndpointAnnouncer.h> +#include "celix/rsa/IEndpointAnnouncer.h" #include <IExportedService.h> #include <celix_api.h> #include <mutex> @@ -46,7 +46,7 @@ namespace celix::async_rsa { void addExportedService(celix::async_rsa::IExportedService *endpoint, Properties&& properties); void removeExportedService(celix::async_rsa::IExportedService *endpoint, Properties&& properties); - void setDiscovery(celix::rsa::EndpointAnnouncer *discovery); + void setDiscovery(celix::rsa::IEndpointAnnouncer *discovery); private: celix_log_helper_t *_logger; @@ -58,6 +58,6 @@ namespace celix::async_rsa { #else std::unordered_map<std::string, celix::async_rsa::IExportedService*> _exportedServices{}; #endif - celix::rsa::EndpointAnnouncer *_discovery{}; + celix::rsa::IEndpointAnnouncer *_discovery{}; }; } \ No newline at end of file diff --git a/bundles/async_remote_services/topology_manager/src/topology_manager.cc b/bundles/async_remote_services/topology_manager/src/topology_manager.cc index c8e031d..5ca4ef4 100644 --- a/bundles/async_remote_services/topology_manager/src/topology_manager.cc +++ b/bundles/async_remote_services/topology_manager/src/topology_manager.cc @@ -39,7 +39,7 @@ celix::async_rsa::AsyncTopologyManager::~AsyncTopologyManager() { } void celix::async_rsa::AsyncTopologyManager::addExportedService(celix::async_rsa::IExportedService *exportedService, Properties &&properties) { - auto interface = properties.get(ENDPOINT_EXPORTS); + auto interface = properties.get(celix::rsa::Endpoint::EXPORTS); if(interface.empty()) { L_DEBUG("Adding exported service but no exported interfaces"); @@ -66,7 +66,7 @@ void celix::async_rsa::AsyncTopologyManager::addExportedService(celix::async_rsa } void celix::async_rsa::AsyncTopologyManager::removeExportedService([[maybe_unused]] celix::async_rsa::IExportedService *exportedService, Properties &&properties) { - auto interface = properties.get(ENDPOINT_EXPORTS); + auto interface = properties.get(celix::rsa::Endpoint::EXPORTS); if(interface.empty()) { L_WARN("Removing exported service but missing exported interfaces"); @@ -85,7 +85,7 @@ void celix::async_rsa::AsyncTopologyManager::removeExportedService([[maybe_unuse } } -void celix::async_rsa::AsyncTopologyManager::setDiscovery(celix::rsa::EndpointAnnouncer *discovery) { +void celix::async_rsa::AsyncTopologyManager::setDiscovery(celix::rsa::IEndpointAnnouncer *discovery) { std::unique_lock l(_m); _discovery = discovery; } @@ -99,7 +99,7 @@ public: .setCallbacks(&celix::async_rsa::AsyncTopologyManager::addExportedService, &celix::async_rsa::AsyncTopologyManager::removeExportedService) .build(); - _cmp.createServiceDependency<celix::rsa::EndpointAnnouncer>() + _cmp.createServiceDependency<celix::rsa::IEndpointAnnouncer>() .setRequired(true) .setCallbacks(&celix::async_rsa::AsyncTopologyManager::setDiscovery) .build(); diff --git a/libs/framework/include/celix/dm/types.h b/libs/framework/include/celix/dm/types.h index c8fca93..16c1de0 100644 --- a/libs/framework/include/celix/dm/types.h +++ b/libs/framework/include/celix/dm/types.h @@ -32,12 +32,12 @@ namespace celix { namespace dm { template<typename T, typename I> class ProvidedService; - template<class T, typename I> - class CServiceDependency; - template<class T, class I> class ServiceDependency; + template<class T, typename I> + class CServiceDependency; + template<typename T> std::string typeName() { return celix::typeName<T>();
