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 2015/11/26 20:56:16 UTC
celix git commit: CELIX-272: Add bundleContext_retainServiceReference
to be able to control the ref count of service references.
Repository: celix
Updated Branches:
refs/heads/develop d7d396a54 -> d8e8fab41
CELIX-272: Add bundleContext_retainServiceReference to be able to control the ref count of service references.
Project: http://git-wip-us.apache.org/repos/asf/celix/repo
Commit: http://git-wip-us.apache.org/repos/asf/celix/commit/d8e8fab4
Tree: http://git-wip-us.apache.org/repos/asf/celix/tree/d8e8fab4
Diff: http://git-wip-us.apache.org/repos/asf/celix/diff/d8e8fab4
Branch: refs/heads/develop
Commit: d8e8fab413489ebd4ab4acae56234010f803f4f3
Parents: d7d396a
Author: Pepijn Noltes <pe...@gmail.com>
Authored: Thu Nov 26 20:56:07 2015 +0100
Committer: Pepijn Noltes <pe...@gmail.com>
Committed: Thu Nov 26 20:56:07 2015 +0100
----------------------------------------------------------------------
.gitignore | 1 +
.../private/include/service_reference_private.h | 2 +
framework/private/src/bundle_context.c | 14 +++
framework/private/src/framework.c | 89 +++++++++++---------
framework/private/src/service_reference.c | 8 ++
framework/private/src/service_registry.c | 23 +++++
framework/private/src/service_tracker.c | 86 +++++++++----------
framework/public/include/bundle_context.h | 41 ++++++++-
framework/public/include/service_registry.h | 1 +
9 files changed, 180 insertions(+), 85 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/celix/blob/d8e8fab4/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index f630756..6c1ab95 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,4 @@ build
*~
*.swp
.idea
+nbproject
http://git-wip-us.apache.org/repos/asf/celix/blob/d8e8fab4/framework/private/include/service_reference_private.h
----------------------------------------------------------------------
diff --git a/framework/private/include/service_reference_private.h b/framework/private/include/service_reference_private.h
index b0b8afb..ab3b219 100644
--- a/framework/private/include/service_reference_private.h
+++ b/framework/private/include/service_reference_private.h
@@ -62,6 +62,8 @@ celix_status_t serviceReference_getReferenceCount(service_reference_pt reference
celix_status_t serviceReference_setService(service_reference_pt ref, void *service);
celix_status_t serviceReference_getService(service_reference_pt reference, void **service);
+celix_status_t serviceReference_getOwner(service_reference_pt reference, bundle_pt *owner);
+
#endif /* SERVICE_REFERENCE_PRIVATE_H_ */
http://git-wip-us.apache.org/repos/asf/celix/blob/d8e8fab4/framework/private/src/bundle_context.c
----------------------------------------------------------------------
diff --git a/framework/private/src/bundle_context.c b/framework/private/src/bundle_context.c
index f84d767..594355c 100644
--- a/framework/private/src/bundle_context.c
+++ b/framework/private/src/bundle_context.c
@@ -191,6 +191,20 @@ celix_status_t bundleContext_getServiceReference(bundle_context_pt context, char
return status;
}
+FRAMEWORK_EXPORT celix_status_t bundleContext_retainServiceReference(bundle_context_pt context, service_reference_pt ref) {
+ celix_status_t status = CELIX_SUCCESS;
+
+ if (context != NULL && ref != NULL) {
+ serviceRegistry_retainServiceReference(context->framework->registry, context->bundle, ref);
+ } else {
+ status = CELIX_ILLEGAL_ARGUMENT;
+ }
+
+ framework_logIfError(logger, status, NULL, "Failed to get service references");
+
+ return status;
+}
+
celix_status_t bundleContext_ungetServiceReference(bundle_context_pt context, service_reference_pt reference) {
celix_status_t status = CELIX_SUCCESS;
http://git-wip-us.apache.org/repos/asf/celix/blob/d8e8fab4/framework/private/src/framework.c
----------------------------------------------------------------------
diff --git a/framework/private/src/framework.c b/framework/private/src/framework.c
index 0823781..8da65d1 100644
--- a/framework/private/src/framework.c
+++ b/framework/private/src/framework.c
@@ -1582,67 +1582,74 @@ celix_status_t fw_removeFrameworkListener(framework_pt framework, bundle_pt bund
}
void fw_serviceChanged(framework_pt framework, service_event_type_e eventType, service_registration_pt registration, properties_pt oldprops) {
- unsigned int i;
- fw_service_listener_pt element;
+ unsigned int i;
+ fw_service_listener_pt element;
- if (arrayList_size(framework->serviceListeners) > 0) {
- for (i = 0; i < arrayList_size(framework->serviceListeners); i++) {
- int matched = 0;
- properties_pt props = NULL;
- bool matchResult = false;
+ if (arrayList_size(framework->serviceListeners) > 0) {
+ for (i = 0; i < arrayList_size(framework->serviceListeners); i++) {
+ int matched = 0;
+ properties_pt props = NULL;
+ bool matchResult = false;
- element = (fw_service_listener_pt) arrayList_get(framework->serviceListeners, i);
- serviceRegistration_getProperties(registration, &props);
- if (element->filter != NULL) {
- filter_match(element->filter, props, &matchResult);
- }
- matched = (element->filter == NULL) || matchResult;
- if (matched) {
- service_reference_pt reference = NULL;
- service_event_pt event;
+ element = (fw_service_listener_pt) arrayList_get(framework->serviceListeners, i);
+ serviceRegistration_getProperties(registration, &props);
+ if (element->filter != NULL) {
+ filter_match(element->filter, props, &matchResult);
+ }
+ matched = (element->filter == NULL) || matchResult;
+ if (matched) {
+ service_reference_pt reference = NULL;
+ service_event_pt event;
- event = (service_event_pt) malloc(sizeof(*event));
+ event = (service_event_pt) malloc(sizeof (*event));
serviceRegistry_getServiceReference(framework->registry, element->bundle, registration, &reference);
+
+
+ //FIXME, TODO need to retain the service ref. If not bundles using the service_listener will crash.
+ //update service_listener users so that they retain references if the keep them.
+ //NOTE: that you are never sure that the UNREGISTERED event will by handle by an service_listener (could be gone))
+ if (eventType == OSGI_FRAMEWORK_SERVICE_EVENT_REGISTERED) {
+ serviceRegistry_retainServiceReference(framework->registry, element->bundle, reference);
+ }
- event->type = eventType;
- event->reference = reference;
+ event->type = eventType;
+ event->reference = reference;
- element->listener->serviceChanged(element->listener, event);
+ element->listener->serviceChanged(element->listener, event);
- if (eventType != OSGI_FRAMEWORK_SERVICE_EVENT_REGISTERED) {
- serviceRegistry_ungetServiceReference(framework->registry, element->bundle, reference);
- }
+ serviceRegistry_ungetServiceReference(framework->registry, element->bundle, reference);
+
if (eventType == OSGI_FRAMEWORK_SERVICE_EVENT_UNREGISTERING) {
- serviceRegistry_ungetServiceReference(framework->registry, element->bundle, reference);
+ serviceRegistry_ungetServiceReference(framework->registry, element->bundle, reference); // to counter retain
}
-
+
free(event);
- } else if (eventType == OSGI_FRAMEWORK_SERVICE_EVENT_MODIFIED) {
- bool matchResult = false;
- int matched = 0;
- if (element->filter != NULL) {
- filter_match(element->filter, oldprops, &matchResult);
- }
- matched = (element->filter == NULL) || matchResult;
- if (matched) {
- service_reference_pt reference = NULL;
- service_event_pt endmatch = (service_event_pt) malloc(sizeof(*endmatch));
+ } else if (eventType == OSGI_FRAMEWORK_SERVICE_EVENT_MODIFIED) {
+ bool matchResult = false;
+ int matched = 0;
+ if (element->filter != NULL) {
+ filter_match(element->filter, oldprops, &matchResult);
+ }
+ matched = (element->filter == NULL) || matchResult;
+ if (matched) {
+ service_reference_pt reference = NULL;
+ service_event_pt endmatch = (service_event_pt) malloc(sizeof (*endmatch));
serviceRegistry_getServiceReference(framework->registry, element->bundle, registration, &reference);
- endmatch->reference = reference;
- endmatch->type = OSGI_FRAMEWORK_SERVICE_EVENT_MODIFIED_ENDMATCH;
- element->listener->serviceChanged(element->listener, endmatch);
+ endmatch->reference = reference;
+ endmatch->type = OSGI_FRAMEWORK_SERVICE_EVENT_MODIFIED_ENDMATCH;
+ element->listener->serviceChanged(element->listener, endmatch);
serviceRegistry_ungetServiceReference(framework->registry, element->bundle, reference);
free(endmatch);
}
- }
- }
- }
+ }
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/celix/blob/d8e8fab4/framework/private/src/service_reference.c
----------------------------------------------------------------------
diff --git a/framework/private/src/service_reference.c b/framework/private/src/service_reference.c
index 9fbee9e..c40d3c2 100644
--- a/framework/private/src/service_reference.c
+++ b/framework/private/src/service_reference.c
@@ -181,6 +181,14 @@ celix_status_t serviceReference_getBundle(service_reference_pt ref, bundle_pt *b
return status;
}
+celix_status_t serviceReference_getOwner(service_reference_pt ref, bundle_pt *owner) {
+ celix_status_t status = CELIX_SUCCESS;
+ celixThreadRwlock_readLock(&ref->lock);
+ *owner = ref->referenceOwner;
+ celixThreadRwlock_unlock(&ref->lock);
+ return status;
+}
+
celix_status_t serviceReference_getServiceRegistration(service_reference_pt ref, service_registration_pt *out) {
celixThreadRwlock_readLock(&ref->lock);
*out = ref->registration;
http://git-wip-us.apache.org/repos/asf/celix/blob/d8e8fab4/framework/private/src/service_registry.c
----------------------------------------------------------------------
diff --git a/framework/private/src/service_registry.c b/framework/private/src/service_registry.c
index 81487f2..b366f53 100644
--- a/framework/private/src/service_registry.c
+++ b/framework/private/src/service_registry.c
@@ -402,6 +402,29 @@ celix_status_t serviceRegistry_getServiceReferences(service_registry_pt registry
return status;
}
+celix_status_t serviceRegistry_retainServiceReference(service_registry_pt registry, bundle_pt bundle, service_reference_pt reference) {
+ celix_status_t status = CELIX_SUCCESS;
+ reference_status_t refStatus;
+ bundle_pt refBundle = NULL;
+
+ celixThreadRwlock_writeLock(®istry->lock);
+ serviceRegistry_checkReference(registry, reference, &refStatus);
+ if (status == REF_ACTIVE) {
+ serviceReference_getOwner(reference, &refBundle);
+ if (refBundle == bundle) {
+ serviceReference_retain(reference);
+ } else {
+ status = CELIX_ILLEGAL_ARGUMENT;
+ fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "cannot retain a service reference from an other bundle (in ref %p) (provided %p).", refBundle, bundle);
+ }
+ } else {
+ serviceRegistry_logIllegalReference(registry, reference, refStatus);
+ }
+ celixThreadRwlock_unlock(®istry->lock);
+
+ return status;
+}
+
celix_status_t serviceRegistry_ungetServiceReference(service_registry_pt registry, bundle_pt bundle, service_reference_pt reference) {
celix_status_t status = CELIX_SUCCESS;
http://git-wip-us.apache.org/repos/asf/celix/blob/d8e8fab4/framework/private/src/service_tracker.c
----------------------------------------------------------------------
diff --git a/framework/private/src/service_tracker.c b/framework/private/src/service_tracker.c
index 7714139..1d4e4aa 100644
--- a/framework/private/src/service_tracker.c
+++ b/framework/private/src/service_tracker.c
@@ -271,51 +271,50 @@ void serviceTracker_serviceChanged(service_listener_pt listener, service_event_p
static celix_status_t serviceTracker_track(service_tracker_pt tracker, service_reference_pt reference, service_event_pt event) {
celix_status_t status = CELIX_SUCCESS;
- tracked_pt tracked = NULL;
- bool found = false;
- unsigned int i;
+ tracked_pt tracked = NULL;
+ bool found = false;
+ unsigned int i;
+
+ bundleContext_retainServiceReference(tracker->context, reference);
celixThreadRwlock_readLock(&tracker->lock);
- for (i = 0; i < arrayList_size(tracker->trackedServices); i++) {
- bool equals = false;
- tracked = (tracked_pt) arrayList_get(tracker->trackedServices, i);
- status = serviceReference_equals(reference, tracked->reference, &equals);
+ for (i = 0; i < arrayList_size(tracker->trackedServices); i++) {
+ bool equals = false;
+ tracked = (tracked_pt) arrayList_get(tracker->trackedServices, i);
+ status = serviceReference_equals(reference, tracked->reference, &equals);
if (status != CELIX_SUCCESS) {
break;
}
- if (equals) {
- found = true;
- break;
- }
- }
+ if (equals) {
+ found = true;
+ break;
+ }
+ }
celixThreadRwlock_unlock(&tracker->lock);
- if (status == CELIX_SUCCESS && !found /*new*/) {
- void * service = NULL;
- status = serviceTracker_invokeAddingService(tracker, reference, &service);
- if (status == CELIX_SUCCESS) {
- if (service != NULL) {
- tracked = (tracked_pt) calloc(1, sizeof(*tracked));
- assert(reference != NULL);
- tracked->reference = reference;
- tracked->service = service;
+ if (status == CELIX_SUCCESS && !found /*new*/) {
+ void * service = NULL;
+ status = serviceTracker_invokeAddingService(tracker, reference, &service);
+ if (status == CELIX_SUCCESS) {
+ if (service != NULL) {
+ tracked = (tracked_pt) calloc(1, sizeof (*tracked));
+ assert(reference != NULL);
+ tracked->reference = reference;
+ tracked->service = service;
serviceTracker_invokeAddService(tracker, reference, service);
celixThreadRwlock_writeLock(&tracker->lock);
arrayList_add(tracker->trackedServices, tracked);
celixThreadRwlock_unlock(&tracker->lock);
- }
- }
+ }
+ }
- } else {
+ } else {
status = serviceTracker_invokeModifiedService(tracker, reference, tracked->service);
- }
-
-
-
+ }
- framework_logIfError(logger, status, NULL, "Cannot track reference");
+ framework_logIfError(logger, status, NULL, "Cannot track reference");
- return status;
+ return status;
}
static celix_status_t serviceTracker_invokeModifiedService(service_tracker_pt tracker, service_reference_pt ref, void *service) {
@@ -380,30 +379,31 @@ static celix_status_t serviceTracker_invokeAddingService(service_tracker_pt trac
}
static celix_status_t serviceTracker_untrack(service_tracker_pt tracker, service_reference_pt reference, service_event_pt event) {
- celix_status_t status = CELIX_SUCCESS;
- tracked_pt tracked = NULL;
- unsigned int i;
+ celix_status_t status = CELIX_SUCCESS;
+ tracked_pt tracked = NULL;
+ unsigned int i;
celixThreadRwlock_writeLock(&tracker->lock);
for (i = 0; i < arrayList_size(tracker->trackedServices); i++) {
- bool equals;
- tracked = (tracked_pt) arrayList_get(tracker->trackedServices, i);
- serviceReference_equals(reference, tracked->reference, &equals);
- if (equals) {
- arrayList_remove(tracker->trackedServices, i);
+ bool equals;
+ tracked = (tracked_pt) arrayList_get(tracker->trackedServices, i);
+ serviceReference_equals(reference, tracked->reference, &equals);
+ if (equals) {
+ arrayList_remove(tracker->trackedServices, i);
break;
- }
- }
+ }
+ }
celixThreadRwlock_unlock(&tracker->lock);
if (tracked != NULL) {
serviceTracker_invokeRemovingService(tracker, tracked->reference, tracked->service);
free(tracked);
+ bundleContext_ungetServiceReference(tracker->context, reference);
}
+
+ framework_logIfError(logger, status, NULL, "Cannot untrack reference");
- framework_logIfError(logger, status, NULL, "Cannot untrack reference");
-
- return status;
+ return status;
}
static celix_status_t serviceTracker_invokeRemovingService(service_tracker_pt tracker, service_reference_pt ref, void *service) {
http://git-wip-us.apache.org/repos/asf/celix/blob/d8e8fab4/framework/public/include/bundle_context.h
----------------------------------------------------------------------
diff --git a/framework/public/include/bundle_context.h b/framework/public/include/bundle_context.h
index 179e601..6c885f5 100644
--- a/framework/public/include/bundle_context.h
+++ b/framework/public/include/bundle_context.h
@@ -55,8 +55,47 @@ FRAMEWORK_EXPORT celix_status_t bundleContext_registerService(bundle_context_pt
FRAMEWORK_EXPORT celix_status_t bundleContext_registerServiceFactory(bundle_context_pt context, char * serviceName, service_factory_pt factory,
properties_pt properties, service_registration_pt *service_registration);
-FRAMEWORK_EXPORT celix_status_t bundleContext_getServiceReferences(bundle_context_pt context, const char * serviceName, char * filter, array_list_pt *service_references);
+/**
+ * Get a service reference for the bundle context. When the service reference is no longer needed use bundleContext_ungetServiceReference.
+ * ServiceReference are coupled to a bundle context. Do not share service reference between bundles. Exchange the service.id instead.
+ *
+ * @param context The bundle context
+ * @param serviceName The name of the service (objectClass) to get
+ * @param service_reference _output_ The found service reference, or NULL when no service is found.
+ * @return CELIX_SUCCESS on success
+ */
FRAMEWORK_EXPORT celix_status_t bundleContext_getServiceReference(bundle_context_pt context, char * serviceName, service_reference_pt *service_reference);
+
+/** Same as bundleContext_getServiceReference, but than for a optional serviceName combined with a optional filter.
+ * The resulting array_list should be destroyed by the caller. For all service references return a unget should be called.
+ *
+ * @param context the bundle context
+ * @param serviceName the serviceName, can be NULL
+ * @param filter the filter, can be NULL. If present will be combined (and) with the serviceName
+ * @param service_references _output_ a array list, can be size 0.
+ * @return CELIX_SUCCESS on success
+ */
+FRAMEWORK_EXPORT celix_status_t bundleContext_getServiceReferences(bundle_context_pt context, const char * serviceName, char * filter, array_list_pt *service_references);
+
+/**
+ * Retains (increases the ref count) the provided service reference. Can be used to retain a service reference.
+ * Note that this is a deviation from the OSGi spec, due to the fact that C has no garbage collect.
+ *
+ * @param context the bundle context
+ * @param reference the service reference to retain
+ * @return CELIX_SUCCES on success
+ */
+FRAMEWORK_EXPORT celix_status_t bundleContext_retainServiceReference(bundle_context_pt context, service_reference_pt reference);
+
+/**
+ * Ungets the service references. If the ref counter of the service refernce goes to 0, the reference will be destroyed.
+ * This is coupled with the bundleContext_getServiceReference(s) and bundleContext_retainServiceReferenc.
+ * Note: That this is a deviation from the OSGi standard, due to the fact that C has no garbage collect.
+ *
+ * @param context The bundle context.
+ * @param reference the service reference to unget
+ * @return CELIX_SUCCESS on success.
+ */
FRAMEWORK_EXPORT celix_status_t bundleContext_ungetServiceReference(bundle_context_pt context, service_reference_pt reference);
FRAMEWORK_EXPORT celix_status_t bundleContext_getService(bundle_context_pt context, service_reference_pt reference, void **service_instance);
http://git-wip-us.apache.org/repos/asf/celix/blob/d8e8fab4/framework/public/include/service_registry.h
----------------------------------------------------------------------
diff --git a/framework/public/include/service_registry.h b/framework/public/include/service_registry.h
index 5c013cc..41560b2 100644
--- a/framework/public/include/service_registry.h
+++ b/framework/public/include/service_registry.h
@@ -52,6 +52,7 @@ celix_status_t serviceRegistry_clearServiceRegistrations(service_registry_pt reg
celix_status_t serviceRegistry_getServiceReference(service_registry_pt registry, bundle_pt bundle, service_registration_pt registration, service_reference_pt *reference);
celix_status_t serviceRegistry_getServiceReferences(service_registry_pt registry, bundle_pt bundle, const char *serviceName, filter_pt filter, array_list_pt *references);
+celix_status_t serviceRegistry_retainServiceReference(service_registry_pt registry, bundle_pt bundle, service_reference_pt reference);
celix_status_t serviceRegistry_ungetServiceReference(service_registry_pt registry, bundle_pt bundle, service_reference_pt reference);
celix_status_t serviceRegistry_getService(service_registry_pt registry, bundle_pt bundle, service_reference_pt reference, void **service);