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);
         }
 

Reply via email to