This is an automated email from the ASF dual-hosted git repository.

pnoltes pushed a commit to branch feature/674-improve-properties
in repository https://gitbox.apache.org/repos/asf/celix.git

commit a555df9711884dd1aac7a557c96bea42fda4e8d6
Author: Pepijn Noltes <[email protected]>
AuthorDate: Sun Jan 21 19:19:53 2024 +0100

    Add automatic conversion of ranking/version props for ctx
---
 .../src/CelixBundleContextServicesTestSuite.cc     | 56 ++++++++++++++++++++++
 libs/framework/src/bundle_context.c                | 53 ++++++++++++++++++++
 2 files changed, 109 insertions(+)

diff --git a/libs/framework/gtest/src/CelixBundleContextServicesTestSuite.cc 
b/libs/framework/gtest/src/CelixBundleContextServicesTestSuite.cc
index d17b3892..f9955f6f 100644
--- a/libs/framework/gtest/src/CelixBundleContextServicesTestSuite.cc
+++ b/libs/framework/gtest/src/CelixBundleContextServicesTestSuite.cc
@@ -1741,3 +1741,59 @@ TEST_F(CelixBundleContextServicesTestSuite, 
SetServicesWithTrackerWhenMultipleRe
     celix_bundleContext_unregisterService(ctx, svcId2);
     celix_bundleContext_unregisterService(ctx, svcId3);
 }
+
+TEST_F(CelixBundleContextServicesTestSuite, 
RegisterServiceWithInvalidRankingAndVersionPropertyTypeTest) {
+    //Given service properties with invalid type for ranking and version
+    celix_properties_t* props = celix_properties_create();
+    celix_properties_set(props, CELIX_FRAMEWORK_SERVICE_RANKING, "10"); 
//string, not long type
+    celix_properties_set(props, CELIX_FRAMEWORK_SERVICE_VERSION, "1.0.0"); 
//string, not celix_version_t* type
+
+    //When registering service
+    long svcId = celix_bundleContext_registerService(ctx, (void*)0x42, 
"TestService", props);
+
+    //Then the registration is successful
+    EXPECT_GE(svcId, 0);
+
+    //And the service properties types are corrected
+    celix_service_use_options_t opts;
+    opts.filter.serviceName = "TestService";
+    opts.useWithProperties = [](void* /*handle*/, void* /*svc*/, const 
celix_properties_t* props) {
+        auto propertyType = celix_properties_getType(props, 
CELIX_FRAMEWORK_SERVICE_RANKING);
+        EXPECT_EQ(CELIX_PROPERTIES_VALUE_TYPE_LONG, propertyType);
+
+        propertyType = celix_properties_getType(props, 
CELIX_FRAMEWORK_SERVICE_VERSION);
+        EXPECT_EQ(CELIX_PROPERTIES_VALUE_TYPE_VERSION, propertyType);
+    };
+    auto count = celix_bundleContext_useServicesWithOptions(ctx, &opts);
+    EXPECT_EQ(1, count);
+
+    celix_bundleContext_unregisterService(ctx, svcId);
+}
+
+TEST_F(CelixBundleContextServicesTestSuite, 
RegisterServiceWithInvalidRankingAndVersionValueTest) {
+    //Given service properties with invalid type for ranking and version
+    celix_properties_t* props = celix_properties_create();
+    celix_properties_set(props, CELIX_FRAMEWORK_SERVICE_RANKING, "foo"); 
//string, not convertable to long
+    celix_properties_set(props, CELIX_FRAMEWORK_SERVICE_VERSION, "bar"); 
//string, not convertable to version
+
+    //When registering service
+    long svcId = celix_bundleContext_registerService(ctx, (void*)0x42, 
"TestService", props);
+
+    //Then the registration is successful
+    EXPECT_GE(svcId, 0);
+
+    //And the service properties typer are kept as-is.
+    celix_service_use_options_t opts;
+    opts.filter.serviceName = "TestService";
+    opts.useWithProperties = [](void* /*handle*/, void* /*svc*/, const 
celix_properties_t* props) {
+        auto propertyType = celix_properties_getType(props, 
CELIX_FRAMEWORK_SERVICE_RANKING);
+        EXPECT_EQ(CELIX_PROPERTIES_VALUE_TYPE_STRING, propertyType);
+
+        propertyType = celix_properties_getType(props, 
CELIX_FRAMEWORK_SERVICE_VERSION);
+        EXPECT_EQ(CELIX_PROPERTIES_VALUE_TYPE_STRING, propertyType);
+    };
+    auto count = celix_bundleContext_useServicesWithOptions(ctx, &opts);
+    EXPECT_EQ(1, count);
+
+    celix_bundleContext_unregisterService(ctx, svcId);
+}
diff --git a/libs/framework/src/bundle_context.c 
b/libs/framework/src/bundle_context.c
index c64e2ca4..86ae2a2a 100644
--- a/libs/framework/src/bundle_context.c
+++ b/libs/framework/src/bundle_context.c
@@ -379,6 +379,52 @@ long 
celix_bundleContext_registerServiceFactory(celix_bundle_context_t *ctx, cel
     return celix_bundleContext_registerServiceWithOptions(ctx, &opts);
 }
 
+/**
+ * Corrects the service properties value types for the service ranking and 
service version to ensure
+ * that these properties are of the correct type.
+ * Print a warning log message if the service ranking or service version was 
not of the correct type.
+ */
+static celix_status_t 
celix_bundleContext_correctServicePropertiesValueTypes(celix_bundle_context_t* 
ctx,
+                                                                             
celix_properties_t* props) {
+    celix_status_t status = CELIX_SUCCESS;
+    const celix_properties_entry_t* entry = celix_properties_getEntry(props, 
CELIX_FRAMEWORK_SERVICE_RANKING);
+    if (entry && entry->valueType == CELIX_PROPERTIES_VALUE_TYPE_STRING) {
+        fw_log(
+            ctx->framework->logger, CELIX_LOG_LEVEL_WARNING, "Service ranking 
is of type string, converting to long");
+        bool converted;
+        long ranking = celix_utils_convertStringToLong(entry->value, 0, 
&converted);
+        if (!converted) {
+            fw_log(ctx->framework->logger,
+                   CELIX_LOG_LEVEL_WARNING,
+                   "Cannot convert service ranking %s to long. Keeping %s 
value as string",
+                   entry->value,
+                   CELIX_FRAMEWORK_SERVICE_RANKING);
+        } else {
+            status = celix_properties_setLong(props, 
CELIX_FRAMEWORK_SERVICE_RANKING, ranking);
+        }
+    }
+
+    entry = celix_properties_getEntry(props, CELIX_FRAMEWORK_SERVICE_VERSION);
+    if (status == CELIX_SUCCESS && entry && entry->valueType == 
CELIX_PROPERTIES_VALUE_TYPE_STRING) {
+        fw_log(ctx->framework->logger,
+               CELIX_LOG_LEVEL_WARNING,
+               "Service version is of type string, converting to version");
+        celix_autoptr(celix_version_t) version = NULL;
+        status = celix_version_parse(entry->value, &version);
+        if (status == CELIX_ILLEGAL_ARGUMENT) {
+            fw_log(ctx->framework->logger,
+                   CELIX_LOG_LEVEL_WARNING,
+                   "Cannot parse service version %s. Keeping %s value as 
string",
+                   entry->value,
+                   CELIX_FRAMEWORK_SERVICE_VERSION);
+            status = CELIX_SUCCESS; //after warning, ignore parse error.
+        } else if (status == CELIX_SUCCESS) {
+            status = celix_properties_assignVersion(props, 
CELIX_FRAMEWORK_SERVICE_VERSION, celix_steal_ptr(version));
+        }
+    }
+    return status;
+}
+
 static long 
celix_bundleContext_registerServiceWithOptionsInternal(bundle_context_t *ctx, 
const celix_service_registration_options_t *opts, bool async) {
     bool valid = opts->serviceName != NULL && strncmp("", opts->serviceName, 
1) != 0;
     if (!valid) {
@@ -414,6 +460,13 @@ static long 
celix_bundleContext_registerServiceWithOptionsInternal(bundle_contex
         }
     }
 
+    celix_status_t correctionStatus = 
celix_bundleContext_correctServicePropertiesValueTypes(ctx, props);
+    if (correctionStatus != CELIX_SUCCESS) {
+        celix_framework_logTssErrors(ctx->framework->logger, 
CELIX_LOG_LEVEL_ERROR);
+        fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Cannot correct 
service properties value types");
+        return -1;
+    }
+
     long svcId;
     if (!async && celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) 
{
         /*

Reply via email to