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(&registry->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(&registry->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);