You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celix.apache.org by pn...@apache.org on 2020/10/05 18:44:00 UTC

[celix] branch feature/async_svc_registration updated: Moves the findService(s) logic to service registry and executes this on the calling thread instead of the event loop.

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

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


The following commit(s) were added to refs/heads/feature/async_svc_registration by this push:
     new 6c10f8e  Moves the findService(s) logic to service registry and executes this on the calling thread instead of the event loop.
6c10f8e is described below

commit 6c10f8edd364c7109bc3354955fa6b1355003de0
Author: Pepijn Noltes <pe...@gmail.com>
AuthorDate: Mon Oct 5 20:43:38 2020 +0200

    Moves the findService(s) logic to service registry and executes this on the calling thread instead of the event loop.
    
    Also fixes an issue in the utils_compareServiceIdsAndRanking function.
---
 .../gtest/src/bundle_context_services_test.cpp     |   7 +-
 libs/framework/include/service_registry.h          |  24 ++++
 libs/framework/src/bundle_context.c                |  49 +++-----
 libs/framework/src/service_registry.c              | 130 +++++++++++++++++++++
 libs/framework/src/service_tracker.c               |  62 ++--------
 libs/utils/private/test/utils_test.cpp             |  16 +--
 libs/utils/src/utils.c                             |   4 +-
 7 files changed, 196 insertions(+), 96 deletions(-)

diff --git a/libs/framework/gtest/src/bundle_context_services_test.cpp b/libs/framework/gtest/src/bundle_context_services_test.cpp
index f20a449..3c0e752 100644
--- a/libs/framework/gtest/src/bundle_context_services_test.cpp
+++ b/libs/framework/gtest/src/bundle_context_services_test.cpp
@@ -966,6 +966,9 @@ TEST_F(CelixBundleContextServicesTests, asyncServiceFactoryTest) {
 TEST_F(CelixBundleContextServicesTests, findServicesTest) {
     long svcId1 = celix_bundleContext_registerService(ctx, (void*)0x100, "example", nullptr);
     long svcId2 = celix_bundleContext_registerService(ctx, (void*)0x100, "example", nullptr);
+    long svcId3 = celix_bundleContext_registerService(ctx, (void*)0x100, "example", nullptr);
+    long svcId4 = celix_bundleContext_registerService(ctx, (void*)0x100, "example", nullptr);
+
 
     long foundId = celix_bundleContext_findService(ctx, "non existing service name");
     ASSERT_EQ(-1L, foundId);
@@ -978,10 +981,12 @@ TEST_F(CelixBundleContextServicesTests, findServicesTest) {
     arrayList_destroy(list);
 
     list = celix_bundleContext_findServices(ctx, "example");
-    ASSERT_EQ(2, celix_arrayList_size(list));
+    ASSERT_EQ(4, celix_arrayList_size(list));
     arrayList_destroy(list);
 
     celix_bundleContext_unregisterService(ctx, svcId1);
+    celix_bundleContext_unregisterService(ctx, svcId3);
+    celix_bundleContext_unregisterService(ctx, svcId4);
 
     celix_service_filter_options_t opts{};
     opts.serviceName = "example";
diff --git a/libs/framework/include/service_registry.h b/libs/framework/include/service_registry.h
index b9f1ad3..275f707 100644
--- a/libs/framework/include/service_registry.h
+++ b/libs/framework/include/service_registry.h
@@ -151,6 +151,30 @@ long celix_serviceRegistry_nextSvcId(celix_service_registry_t* registry);
 void celix_serviceRegistry_unregisterService(celix_service_registry_t* registry, celix_bundle_t* bnd, long serviceId);
 
 
+/**
+ * Create a LDAP filter for the provided filter parts.
+ * @param serviceName       The optional service name
+ * @param versionRange      The optional version range
+ * @param filter            The optional filter
+ * @param serviceLanguage   The optional service lang. if NULL, lang C will be used.
+ * @param ignoreServiceLanguage   The whether the service lang filter needs to be added to the filter.
+ * @return a LDAP filter. Caller is responsible for freeing the filter.
+ */
+char* celix_serviceRegistry_createFilterFor(
+        celix_service_registry_t* registry,
+        const char* serviceName,
+        const char* versionRange,
+        const char* additionalFilter,
+        const char* serviceLanguage,
+        bool ignoreServiceLanguage);
+
+/**
+ * Find services and return a array list of service ids (long).
+ * Caller is responsible for freeing the returned array list.
+ */
+celix_array_list_t* celix_serviceRegisrty_findServices(celix_service_registry_t* registry, const char* filter);
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/libs/framework/src/bundle_context.c b/libs/framework/src/bundle_context.c
index 34a3dcb..18b0af5 100644
--- a/libs/framework/src/bundle_context.c
+++ b/libs/framework/src/bundle_context.c
@@ -1295,10 +1295,6 @@ static long celix_bundleContext_trackServicesWithOptionsInternal(celix_bundle_co
 
     if (!async && celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) {
         //already in event loop thread. To keep the old behavior just create the tracker traditionally (chained in the current thread).
-        if (opts->filter.serviceName == NULL) {
-            fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_DEBUG, "Starting a tracker for any services");
-        }
-
         celix_service_tracker_t *tracker = celix_serviceTracker_createWithOptions(ctx, opts);
         long trackerId = -1L;
         if (tracker != NULL) {
@@ -1352,19 +1348,19 @@ long celix_bundleContext_findService(celix_bundle_context_t *ctx, const char *se
     return celix_bundleContext_findServiceWithOptions(ctx, &opts);
 }
 
-static void bundleContext_retrieveSvcId(void *handle, void *svc __attribute__((unused)), const celix_properties_t *props) {
-    long *svcId = handle;
-    *svcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, -1L);
-}
-
 long celix_bundleContext_findServiceWithOptions(celix_bundle_context_t *ctx, const celix_service_filter_options_t *opts) {
-    long svcId = -1L;
-    celix_service_use_options_t useOpts = CELIX_EMPTY_SERVICE_USE_OPTIONS;
-    memcpy(&useOpts.filter, opts, sizeof(useOpts.filter));
-    useOpts.callbackHandle = &svcId;
-    useOpts.useWithProperties = bundleContext_retrieveSvcId;
-    celix_bundleContext_useServiceWithOptions(ctx, &useOpts);
-    return svcId;
+    long result = -1L;
+    char* filter = celix_serviceRegistry_createFilterFor(ctx->framework->registry, opts->serviceName, opts->versionRange, opts->filter, opts->serviceLanguage, opts->ignoreServiceLanguage);
+    if (filter != NULL) {
+        celix_array_list_t *svcIds = celix_serviceRegisrty_findServices(ctx->framework->registry, filter);
+        if (svcIds != NULL && celix_arrayList_size(svcIds) > 0) {
+            result = celix_arrayList_getLong(svcIds, 0);
+        }
+        if (svcIds != NULL) {
+            celix_arrayList_destroy(svcIds);
+        }
+    }
+    return result;
 }
 
 
@@ -1374,22 +1370,13 @@ celix_array_list_t* celix_bundleContext_findServices(celix_bundle_context_t *ctx
     return celix_bundleContext_findServicesWithOptions(ctx, &opts);
 }
 
-static void bundleContext_retrieveSvcIds(void *handle, void *svc __attribute__((unused)), const celix_properties_t *props) {
-    celix_array_list_t *list = handle;
-    if (list != NULL) {
-        long svcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, -1L);
-        celix_arrayList_addLong(list, svcId);
-    }
-}
-
 celix_array_list_t* celix_bundleContext_findServicesWithOptions(celix_bundle_context_t *ctx, const celix_service_filter_options_t *opts) {
-    celix_array_list_t* list = celix_arrayList_create();
-    celix_service_use_options_t useOpts = CELIX_EMPTY_SERVICE_USE_OPTIONS;
-    memcpy(&useOpts.filter, opts, sizeof(useOpts.filter));
-    useOpts.callbackHandle = list;
-    useOpts.useWithProperties = bundleContext_retrieveSvcIds;
-    celix_bundleContext_useServicesWithOptions(ctx, &useOpts);
-    return list;
+    celix_array_list_t* result = NULL;
+    char* filter = celix_serviceRegistry_createFilterFor(ctx->framework->registry, opts->serviceName, opts->versionRange, opts->filter, opts->serviceLanguage, opts->ignoreServiceLanguage);
+    if (filter != NULL) {
+        result = celix_serviceRegisrty_findServices(ctx->framework->registry, filter);
+    }
+    return result;
 }
 
 static celix_status_t bundleContext_callServicedTrackerTrackerCallback(void *handle, celix_array_list_t *listeners, bool add) {
diff --git a/libs/framework/src/service_registry.c b/libs/framework/src/service_registry.c
index 1034210..43a052a 100644
--- a/libs/framework/src/service_registry.c
+++ b/libs/framework/src/service_registry.c
@@ -920,6 +920,136 @@ static inline void celix_waitAndDestroyServiceListener(celix_service_registry_se
     free(entry);
 }
 
+/**
+ * Create a LDAP filter for the provided filter parts.
+ * @param serviceName       The optional service name
+ * @param versionRange      The optional version range
+ * @param filter            The optional filter
+ * @param serviceLanguage   The optional service lang. if NULL, lang C will be used.
+ * @param ignoreServiceLanguage   The whether the service lang filter needs to be added to the filter.
+ * @return a LDAP filter. Caller is responsible for freeing the filter.
+ */
+char* celix_serviceRegistry_createFilterFor(celix_service_registry_t* registry, const char* serviceName, const char* versionRangeStr, const char* additionalFilterIn, const char* lang, bool ignoreServiceLanguage) {
+    char* filter = NULL;
+
+    //setting lang
+    if (lang == NULL || strncmp("", lang, 1) == 0) {
+        lang = CELIX_FRAMEWORK_SERVICE_C_LANGUAGE;
+    }
+
+    if (serviceName == NULL) {
+        serviceName = "*";
+    }
+
+    char* versionRange = NULL;
+    if (versionRangeStr != NULL) {
+        version_range_pt range;
+        celix_status_t status = versionRange_parse(versionRangeStr, &range);
+        if(status != CELIX_SUCCESS) {
+            framework_log(registry->framework->logger, CELIX_LOG_LEVEL_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__,
+                          "Error incorrect version range.");
+            return NULL;
+        }
+        versionRange = versionRange_createLDAPFilter(range, CELIX_FRAMEWORK_SERVICE_VERSION);
+        versionRange_destroy(range);
+        if (versionRange == NULL) {
+            framework_log(registry->framework->logger, CELIX_LOG_LEVEL_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__,
+                          "Error creating LDAP filter.");
+            return NULL;
+        }
+    }
+
+    //setting filter
+    if (ignoreServiceLanguage) {
+        if (additionalFilterIn != NULL && versionRange != NULL) {
+            asprintf(&filter, "(&(%s=%s)%s%s)", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, versionRange, additionalFilterIn);
+        } else if (versionRange != NULL) {
+            asprintf(&filter, "(&(%s=%s)%s)", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, versionRange);
+        } else if (additionalFilterIn != NULL) {
+            asprintf(&filter, "(&(%s=%s)%s)", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, additionalFilterIn);
+        } else {
+            asprintf(&filter, "(&(%s=%s))", OSGI_FRAMEWORK_OBJECTCLASS, serviceName);
+        }
+    } else {
+        if (additionalFilterIn != NULL && versionRange != NULL) {
+            asprintf(&filter, "(&(%s=%s)(%s=%s)%s%s)", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang, versionRange, additionalFilterIn);
+        } else if (versionRange != NULL) {
+            asprintf(&filter, "(&(%s=%s)(%s=%s)%s)", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang, versionRange);
+        } else if (additionalFilterIn != NULL) {
+            asprintf(&filter, "(&(%s=%s)(%s=%s)%s)", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang, additionalFilterIn);
+        } else {
+            asprintf(&filter, "(&(%s=%s)(%s=%s))", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang);
+        }
+    }
+
+    if (versionRange != NULL){
+        free(versionRange);
+    }
+
+    return filter;
+}
+
+static int celix_serviceRegistry_compareRegistrations(const void *a, const void *b) {
+    const service_registration_t* regA = a;
+    const service_registration_t* regB = b;
+
+    celix_properties_t* propsA = NULL;
+    celix_properties_t* propsB = NULL;
+    serviceRegistration_getProperties((service_registration_t*)regA, &propsA);
+    serviceRegistration_getProperties((service_registration_t*)regB, &propsB);
+
+    long servIdA = celix_properties_getAsLong(propsA, OSGI_FRAMEWORK_SERVICE_ID, 0);
+    long servIdB = celix_properties_getAsLong(propsB, OSGI_FRAMEWORK_SERVICE_ID, 0);
+
+    long servRankingA = celix_properties_getAsLong(propsA, OSGI_FRAMEWORK_SERVICE_RANKING, 0);
+    long servRankingB = celix_properties_getAsLong(propsB, OSGI_FRAMEWORK_SERVICE_RANKING, 0);
+
+    return utils_compareServiceIdsAndRanking(servIdA, servRankingA, servIdB, servRankingB);
+}
+
+celix_array_list_t* celix_serviceRegisrty_findServices(
+        celix_service_registry_t* registry,
+        const char* filterStr) {
+
+    celix_filter_t* filter = celix_filter_create(filterStr);
+    if (filter == NULL) {
+        framework_log(registry->framework->logger, CELIX_LOG_LEVEL_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__,
+                      "Error incorrect filter.");
+        return NULL;
+    }
+
+    celix_array_list_t *result = celix_arrayList_create();
+    celix_array_list_t* matchedRegistrations = celix_arrayList_create();
+
+    celixThreadRwlock_readLock(&registry->lock);
+
+    hash_map_iterator_t iter = hashMapIterator_construct(registry->serviceRegistrations);
+    while (hashMapIterator_hasNext(&iter)) {
+        celix_array_list_t *regs = hashMapIterator_nextValue(&iter);
+        for (int i = 0; i < celix_arrayList_size(regs); ++i) {
+            service_registration_t *reg = celix_arrayList_get(regs, i);
+            celix_properties_t* svcProps = NULL;
+            serviceRegistration_getProperties(reg, &svcProps);
+            if (svcProps != NULL && celix_filter_match(filter, svcProps)) {
+                celix_arrayList_add(matchedRegistrations, reg);
+            }
+        }
+    }
+
+    //sort matched registration and add the svc id to the result list.
+    celix_arrayList_sort(matchedRegistrations, celix_serviceRegistry_compareRegistrations);
+    for (int i = 0; i < celix_arrayList_size(matchedRegistrations); ++i) {
+        service_registration_t* reg = celix_arrayList_get(matchedRegistrations, i);
+        celix_arrayList_addLong(result, serviceRegistration_getServiceId(reg));
+    }
+
+    celixThreadRwlock_unlock(&registry->lock);
+
+    celix_filter_destroy(filter);
+    celix_arrayList_destroy(matchedRegistrations);
+    return result;
+}
+
 
 celix_array_list_t* celix_serviceRegistry_listServiceIdsForOwner(celix_service_registry_t* registry, long bndId) {
     celix_array_list_t *result = celix_arrayList_create();
diff --git a/libs/framework/src/service_tracker.c b/libs/framework/src/service_tracker.c
index 69cfb32..4a47397 100644
--- a/libs/framework/src/service_tracker.c
+++ b/libs/framework/src/service_tracker.c
@@ -658,60 +658,14 @@ celix_service_tracker_t* celix_serviceTracker_createWithOptions(
 
             tracker->listener.handle = tracker;
             tracker->listener.serviceChanged = (void *) serviceTracker_serviceChanged;
-
-            //setting lang
-            const char *lang = opts->filter.serviceLanguage;
-            if (lang == NULL || strncmp("", lang, 1) == 0) {
-                lang = CELIX_FRAMEWORK_SERVICE_C_LANGUAGE;
-            }
-
-            char* versionRange = NULL;
-            if(opts->filter.versionRange != NULL) {
-                version_range_pt range;
-                celix_status_t status = versionRange_parse(opts->filter.versionRange, &range);
-                if(status != CELIX_SUCCESS) {
-                    framework_log(tracker->context->framework->logger, CELIX_LOG_LEVEL_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__,
-                    "Error incorrect version range.");
-                    free(tracker->serviceName);
-                    free(tracker);
-                    return NULL;
-                }
-                versionRange = versionRange_createLDAPFilter(range, CELIX_FRAMEWORK_SERVICE_VERSION);
-                versionRange_destroy(range);
-                if(versionRange == NULL) {
-                    framework_log(tracker->context->framework->logger, CELIX_LOG_LEVEL_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__,
-                                  "Error creating LDAP filter.");
-                    free(tracker->serviceName);
-                    free(tracker);
-                    return NULL;
-                }
-            }
-
-            //setting filter
-            if (opts->filter.ignoreServiceLanguage) {
-                if (opts->filter.filter != NULL && versionRange != NULL) {
-                    asprintf(&tracker->filter, "(&(%s=%s)%s%s)", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, versionRange, opts->filter.filter);
-                } else if (versionRange != NULL) {
-                    asprintf(&tracker->filter, "(&(%s=%s)%s)", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, versionRange);
-                } else if (opts->filter.filter != NULL) {
-                    asprintf(&tracker->filter, "(&(%s=%s)%s)", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, opts->filter.filter);
-                } else {
-                    asprintf(&tracker->filter, "(&(%s=%s))", OSGI_FRAMEWORK_OBJECTCLASS, serviceName);
-                }
-            } else {
-                if (opts->filter.filter != NULL && versionRange != NULL) {
-                    asprintf(&tracker->filter, "(&(%s=%s)(%s=%s)%s%s)", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang, versionRange, opts->filter.filter);
-                } else if (versionRange != NULL) {
-                    asprintf(&tracker->filter, "(&(%s=%s)(%s=%s)%s)", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang, versionRange);
-                } else if (opts->filter.filter != NULL) {
-                    asprintf(&tracker->filter, "(&(%s=%s)(%s=%s)%s)", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang, opts->filter.filter);
-                } else {
-                    asprintf(&tracker->filter, "(&(%s=%s)(%s=%s))", OSGI_FRAMEWORK_OBJECTCLASS, serviceName, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang);
-                }
-            }
-
-            if (versionRange != NULL){
-                free(versionRange);
+            tracker->filter = celix_serviceRegistry_createFilterFor(ctx->framework->registry, opts->filter.serviceName, opts->filter.versionRange, opts->filter.filter, opts->filter.serviceLanguage, opts->filter.ignoreServiceLanguage);
+
+            if (tracker->filter == NULL) {
+                framework_log(tracker->context->framework->logger, CELIX_LOG_LEVEL_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__,
+                              "Error cannot create filter.");
+                free(tracker->serviceName);
+                free(tracker);
+                return NULL;
             }
 
             serviceTracker_open(tracker);
diff --git a/libs/utils/private/test/utils_test.cpp b/libs/utils/private/test/utils_test.cpp
index dfd9066..0954b38 100644
--- a/libs/utils/private/test/utils_test.cpp
+++ b/libs/utils/private/test/utils_test.cpp
@@ -271,21 +271,21 @@ TEST(utils, isNumeric) {
 
 TEST(utils, compareServiceIdsAndRanking){
     int ret;
-    //service 1 is higher ranked and has a irrelevant ID
+    //service 1 is higher ranked and has a irrelevant ID, so result is -1 (smaller -> sorted before service 2)
     ret = utils_compareServiceIdsAndRanking(2,2,1,1);
-    LONGS_EQUAL(1, ret);
+    LONGS_EQUAL(-1, ret);
 
-    //service 1 is equally ranked and has a lower ID
+    //service 1 is equally ranked and has a lower ID. so result is -1 (smaller -> sorted before service 2)
     ret = utils_compareServiceIdsAndRanking(1,1,2,1);
-    LONGS_EQUAL(1, ret);
+    LONGS_EQUAL(-1, ret);
 
-    //service 1 is equally ranked and has a higher ID
+    //service 1 is equally ranked and has a higher ID, so result is 1 (larger -> sorted after service 2)
     ret = utils_compareServiceIdsAndRanking(2,1,1,1);
-    LONGS_EQUAL(-1, ret);
+    LONGS_EQUAL(1, ret);
 
-    //service 1 is lower ranked and has a irrelevant ID
+    //service 1 is lower ranked and has a irrelevant ID, so result is -1 (larger -> sorted after service 2)
     ret = utils_compareServiceIdsAndRanking(1,1,2,2);
-    LONGS_EQUAL(-1, ret);
+    LONGS_EQUAL(1, ret);
 
     //service 1 is equal in ID and irrelevantly ranked
     ret = utils_compareServiceIdsAndRanking(1,1,1,1);
diff --git a/libs/utils/src/utils.c b/libs/utils/src/utils.c
index f82bd26..e333659 100644
--- a/libs/utils/src/utils.c
+++ b/libs/utils/src/utils.c
@@ -150,9 +150,9 @@ int utils_compareServiceIdsAndRanking(unsigned long servId, long servRank, unsig
     if (servId == otherServId) {
         result = 0;
     } else if (servRank != otherServRank) {
-        result = servRank < otherServRank ? -1 : 1;
+        result = servRank < otherServRank ? 1 : -1;
     } else { //equal service rank, compare service ids
-        result = servId < otherServId ? 1 : -1;
+        result = servId < otherServId ? -1 : 1;
     }
 
     return result;