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 <pepijnnol...@gmail.com>
Authored: Thu Nov 26 20:56:07 2015 +0100
Committer: Pepijn Noltes <pepijnnol...@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);

Reply via email to