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(®istry->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(®istry->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;