celix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pnol...@apache.org
Subject [14/46] celix git commit: CELIX-417: Initial refactoring for CMake usage
Date Mon, 20 Nov 2017 20:33:11 GMT
http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/framework/src/resolver.c
----------------------------------------------------------------------
diff --git a/framework/src/resolver.c b/framework/src/resolver.c
new file mode 100644
index 0000000..256eff5
--- /dev/null
+++ b/framework/src/resolver.c
@@ -0,0 +1,495 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+/*
+ * resolver.c
+ *
+ *  \date       Jul 13, 2010
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "resolver.h"
+#include "linked_list_iterator.h"
+#include "bundle.h"
+#include "celix_log.h"
+
+struct capabilityList {
+    char * serviceName;
+    linked_list_pt capabilities;
+};
+
+typedef struct capabilityList * capability_list_pt;
+
+struct candidateSet {
+    module_pt module;
+    requirement_pt requirement;
+    linked_list_pt candidates;
+};
+
+typedef struct candidateSet * candidate_set_pt;
+
+// List containing module_ts
+linked_list_pt m_modules = NULL;
+// List containing capability_t_LISTs
+linked_list_pt m_unresolvedServices = NULL;
+// List containing capability_t_LISTs
+linked_list_pt m_resolvedServices = NULL;
+
+int resolver_populateCandidatesMap(hash_map_pt candidatesMap, module_pt targetModule);
+capability_list_pt resolver_getCapabilityList(linked_list_pt list, const char* name);
+void resolver_removeInvalidCandidate(module_pt module, hash_map_pt candidates, linked_list_pt invalid);
+linked_list_pt resolver_populateWireMap(hash_map_pt candidates, module_pt importer, linked_list_pt wireMap);
+
+linked_list_pt resolver_resolve(module_pt root) {
+    hash_map_pt candidatesMap = NULL;
+    linked_list_pt wireMap = NULL;
+    linked_list_pt resolved = NULL;
+    hash_map_iterator_pt iter = NULL;
+
+    if (module_isResolved(root)) {
+        return NULL;
+    }
+
+    candidatesMap = hashMap_create(NULL, NULL, NULL, NULL);
+
+    if (resolver_populateCandidatesMap(candidatesMap, root) != 0) {
+        hash_map_iterator_pt iter = hashMapIterator_create(candidatesMap);
+        while (hashMapIterator_hasNext(iter)) {
+            hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
+            linked_list_pt value = hashMapEntry_getValue(entry);
+            hashMapIterator_remove(iter);
+            if (value != NULL) {
+                linked_list_iterator_pt candSetIter = linkedListIterator_create(value, 0);
+                while (linkedListIterator_hasNext(candSetIter)) {
+                    candidate_set_pt set = linkedListIterator_next(candSetIter);
+                    linkedList_destroy(set->candidates);
+                    free(set);
+                    linkedListIterator_remove(candSetIter);
+                }
+                linkedListIterator_destroy(candSetIter);
+                linkedList_destroy(value);
+            }
+        }
+        hashMapIterator_destroy(iter);
+        hashMap_destroy(candidatesMap, false, false);
+        return NULL;
+    }
+
+    linkedList_create(&wireMap);
+    resolved = resolver_populateWireMap(candidatesMap, root, wireMap);
+    iter = hashMapIterator_create(candidatesMap);
+    while (hashMapIterator_hasNext(iter)) {
+        hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
+        linked_list_pt value = hashMapEntry_getValue(entry);
+        hashMapIterator_remove(iter);
+        if (value != NULL) {
+            linked_list_iterator_pt candSetIter = linkedListIterator_create(value, 0);
+            while (linkedListIterator_hasNext(candSetIter)) {
+                candidate_set_pt set = linkedListIterator_next(candSetIter);
+                linkedList_destroy(set->candidates);
+                free(set);
+                linkedListIterator_remove(candSetIter);
+            }
+            linkedListIterator_destroy(candSetIter);
+            linkedList_destroy(value);
+        }
+    }
+    hashMapIterator_destroy(iter);
+    hashMap_destroy(candidatesMap, false, false);
+    return resolved;
+}
+
+int resolver_populateCandidatesMap(hash_map_pt candidatesMap, module_pt targetModule) {
+    linked_list_pt candSetList;
+    linked_list_pt candidates;
+    linked_list_pt invalid;
+
+    if (hashMap_containsKey(candidatesMap, targetModule)) {
+        return 0;
+    }
+
+    hashMap_put(candidatesMap, targetModule, NULL);
+
+    if (linkedList_create(&candSetList) == CELIX_SUCCESS) {
+        int i;
+        for (i = 0; i < linkedList_size(module_getRequirements(targetModule)); i++) {
+            capability_list_pt capList;
+            requirement_pt req;
+            const char *targetName = NULL;
+            req = (requirement_pt) linkedList_get(module_getRequirements(targetModule), i);
+            requirement_getTargetName(req, &targetName);
+            capList = resolver_getCapabilityList(m_resolvedServices, targetName);
+
+            if (linkedList_create(&candidates) == CELIX_SUCCESS) {
+                int c;
+                for (c = 0; (capList != NULL) && (c < linkedList_size(capList->capabilities)); c++) {
+                    capability_pt cap = (capability_pt) linkedList_get(capList->capabilities, c);
+                    bool satisfied = false;
+                    requirement_isSatisfied(req, cap, &satisfied);
+                    if (satisfied) {
+                        linkedList_addElement(candidates, cap);
+                    }
+                }
+                capList = resolver_getCapabilityList(m_unresolvedServices, targetName);
+                for (c = 0; (capList != NULL) && (c < linkedList_size(capList->capabilities)); c++) {
+                    capability_pt cap = (capability_pt) linkedList_get(capList->capabilities, c);
+                    bool satisfied = false;
+                    requirement_isSatisfied(req, cap, &satisfied);
+                    if (satisfied) {
+                        linkedList_addElement(candidates, cap);
+                    }
+                }
+
+                if (linkedList_size(candidates) > 0) {
+                    linked_list_iterator_pt iterator = NULL;
+                    for (iterator = linkedListIterator_create(candidates, 0); linkedListIterator_hasNext(iterator);) {
+                        capability_pt candidate = (capability_pt) linkedListIterator_next(iterator);
+                        module_pt module = NULL;
+                        capability_getModule(candidate, &module);
+                        if (!module_isResolved(module)) {
+                            if (resolver_populateCandidatesMap(candidatesMap, module) != 0) {
+                                linkedListIterator_remove(iterator);
+                            }
+                        }
+                    }
+                    linkedListIterator_destroy(iterator);
+                }
+
+                if (linkedList_size(candidates) == 0) {
+                    if (linkedList_create(&invalid) == CELIX_SUCCESS) {
+                        const char *name = NULL;
+                        resolver_removeInvalidCandidate(targetModule, candidatesMap, invalid);
+
+                        module_getSymbolicName(targetModule, &name);
+
+                        linkedList_destroy(invalid);
+                        fw_log(logger, OSGI_FRAMEWORK_LOG_INFO, "Unable to resolve: %s, %s\n", name, targetName);
+                    }
+                    linkedList_destroy(candidates);
+                    linkedList_destroy(candSetList);
+                    return -1;
+                } else if (linkedList_size(candidates) > 0) {
+                    candidate_set_pt cs = (candidate_set_pt) malloc(sizeof(*cs));
+                    cs->candidates = candidates;
+                    cs->module = targetModule;
+                    cs->requirement = req;
+                    linkedList_addElement(candSetList, cs);
+                }
+
+            }
+        }
+        hashMap_put(candidatesMap, targetModule, candSetList);
+    }
+    return 0;
+}
+
+void resolver_removeInvalidCandidate(module_pt invalidModule, hash_map_pt candidates, linked_list_pt invalid) {
+    hash_map_iterator_pt iterator;
+    hashMap_remove(candidates, invalidModule);
+
+    for (iterator = hashMapIterator_create(candidates); hashMapIterator_hasNext(iterator);) {
+        hash_map_entry_pt entry = hashMapIterator_nextEntry(iterator);
+        linked_list_pt candSetList = (linked_list_pt) hashMapEntry_getValue(entry);
+        if (candSetList != NULL) {
+            linked_list_iterator_pt itCandSetList;
+            for (itCandSetList = linkedListIterator_create(candSetList, 0); linkedListIterator_hasNext(itCandSetList);) {
+                candidate_set_pt set = (candidate_set_pt) linkedListIterator_next(itCandSetList);
+                linked_list_iterator_pt candIter;
+                for (candIter = linkedListIterator_create(set->candidates, 0); linkedListIterator_hasNext(candIter);) {
+                    capability_pt candCap = (capability_pt) linkedListIterator_next(candIter);
+                    module_pt module = NULL;
+                    capability_getModule(candCap, &module);
+                    if (module == invalidModule) {
+                        linkedListIterator_remove(candIter);
+                        if (linkedList_size(set->candidates) == 0) {
+                            linkedListIterator_remove(itCandSetList);
+                            if (module != invalidModule && linkedList_contains(invalid, module)) {
+                                linkedList_addElement(invalid, module);
+                            }
+                        }
+                        break;
+                    }
+                }
+                linkedListIterator_destroy(candIter);
+            }
+            linkedListIterator_destroy(itCandSetList);
+        }
+    }
+    hashMapIterator_destroy(iterator);
+
+    if (linkedList_size(invalid) > 0) {
+        while (!linkedList_isEmpty(invalid)) {
+            module_pt m = (module_pt) linkedList_removeIndex(invalid, 0);
+            resolver_removeInvalidCandidate(m, candidates, invalid);
+        }
+    }
+}
+
+void resolver_addModule(module_pt module) {
+
+    if (m_modules == NULL) {
+        linkedList_create(&m_modules);
+        linkedList_create(&m_unresolvedServices);
+        linkedList_create(&m_resolvedServices);
+    }
+
+    if (m_modules != NULL && m_unresolvedServices != NULL) {
+        int i;
+
+        linkedList_addElement(m_modules, module);
+
+        for (i = 0; i < linkedList_size(module_getCapabilities(module)); i++) {
+            const char *serviceName = NULL;
+            capability_list_pt list = NULL;
+            capability_pt cap;
+
+            cap = (capability_pt) linkedList_get(module_getCapabilities(module), i);
+            capability_getServiceName(cap, &serviceName);
+            list = resolver_getCapabilityList(m_unresolvedServices, serviceName);
+            if (list == NULL) {
+                list = (capability_list_pt) malloc(sizeof(*list));
+                if (list != NULL) {
+                    list->serviceName = strdup(serviceName);
+                    if (linkedList_create(&list->capabilities) == CELIX_SUCCESS) {
+                        linkedList_addElement(m_unresolvedServices, list);
+                    }
+                    else{
+                    	free(list->serviceName);
+                    	free(list);
+			list=NULL;
+                    }
+                }
+            }
+            if(list != NULL){
+		linkedList_addElement(list->capabilities, cap);
+            }
+        }
+    }
+}
+
+void resolver_removeModule(module_pt module) {
+    linked_list_pt caps = NULL;
+    linkedList_removeElement(m_modules, module);
+    caps = module_getCapabilities(module);
+    if (caps != NULL) {
+        int i = 0;
+        for (i = 0; i < linkedList_size(caps); i++) {
+            capability_pt cap = (capability_pt) linkedList_get(caps, i);
+            const char *serviceName = NULL;
+            capability_list_pt list;
+            capability_getServiceName(cap, &serviceName);
+            list = resolver_getCapabilityList(m_unresolvedServices, serviceName);
+            if (list != NULL) {
+                linkedList_removeElement(list->capabilities, cap);
+
+                if (linkedList_isEmpty(list->capabilities)) {
+                    linkedList_removeElement(m_unresolvedServices, list);
+                    linkedList_destroy(list->capabilities);
+                    free(list->serviceName);
+                    free(list);
+                }
+            }
+            list = resolver_getCapabilityList(m_resolvedServices, serviceName);
+            if (list != NULL) {
+                linkedList_removeElement(list->capabilities, cap);
+
+                if (linkedList_isEmpty(list->capabilities)) {
+                    linkedList_removeElement(m_resolvedServices, list);
+                    linkedList_destroy(list->capabilities);
+                    free(list->serviceName);
+                    free(list);
+                }
+            }
+        }
+    }
+    if (linkedList_isEmpty(m_modules)) {
+        linkedList_destroy(m_modules);
+        m_modules = NULL;
+
+        if (!linkedList_isEmpty(m_unresolvedServices)) {
+            // #TODO: Something is wrong, not all modules have been removed from the resolver
+            fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Unexpected entries in unresolved module list");
+        }
+        linkedList_destroy(m_unresolvedServices);
+        m_unresolvedServices = NULL;
+        if (!linkedList_isEmpty(m_resolvedServices)) {
+            // #TODO: Something is wrong, not all modules have been removed from the resolver
+            fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Unexpected entries in resolved module list");
+        }
+        linkedList_destroy(m_resolvedServices);
+        m_resolvedServices = NULL;
+    }
+}
+
+void resolver_moduleResolved(module_pt module) {
+
+    if (module_isResolved(module)) {
+        linked_list_pt capsCopy = NULL;
+
+        if (linkedList_create(&capsCopy) == CELIX_SUCCESS) {
+            linked_list_pt wires = NULL;
+            int capIdx;
+
+            for (capIdx = 0; (module_getCapabilities(module) != NULL) && (capIdx < linkedList_size(module_getCapabilities(module))); capIdx++) {
+                capability_pt cap = (capability_pt) linkedList_get(module_getCapabilities(module), capIdx);
+                const char *serviceName = NULL;
+                capability_list_pt list;
+                capability_getServiceName(cap, &serviceName);
+                list = resolver_getCapabilityList(m_unresolvedServices, serviceName);
+                if(list != NULL){
+			linkedList_removeElement(list->capabilities, cap);
+                }
+
+                linkedList_addElement(capsCopy, cap);
+            }
+
+            wires = module_getWires(module);
+            for (capIdx = 0; (capsCopy != NULL) && (capIdx < linkedList_size(capsCopy)); capIdx++) {
+                capability_pt cap = linkedList_get(capsCopy, capIdx);
+
+                int wireIdx = 0;
+                for (wireIdx = 0; (wires != NULL) && (wireIdx < linkedList_size(wires)); wireIdx++) {
+                    wire_pt wire = (wire_pt) linkedList_get(wires, wireIdx);
+                    requirement_pt req = NULL;
+                    bool satisfied = false;
+                    wire_getRequirement(wire, &req);
+                    requirement_isSatisfied(req, cap, &satisfied);
+                    if (satisfied) {
+                        linkedList_set(capsCopy, capIdx, NULL);
+                        break;
+                    }
+                }
+            }
+
+            for (capIdx = 0; (capsCopy != NULL) && (capIdx < linkedList_size(capsCopy)); capIdx++) {
+                capability_pt cap = linkedList_get(capsCopy, capIdx);
+
+                if (cap != NULL) {
+                    const char *serviceName = NULL;
+                    capability_list_pt list = NULL;
+                    capability_getServiceName(cap, &serviceName);
+
+                    list = resolver_getCapabilityList(m_resolvedServices, serviceName);
+                    if (list == NULL) {
+                        list = (capability_list_pt) malloc(sizeof(*list));
+                        if (list != NULL) {
+                            list->serviceName = strdup(serviceName);
+                            if (linkedList_create(&list->capabilities) == CELIX_SUCCESS) {
+                                linkedList_addElement(m_resolvedServices, list);
+                            }
+                            else{
+                            	free(list->serviceName);
+                            	free(list);
+				list=NULL;
+                            }
+                        }
+                    }
+                    if(list != NULL){
+			linkedList_addElement(list->capabilities, cap);
+                    }
+                }
+            }
+
+            linkedList_destroy(capsCopy);
+        }
+    }
+}
+
+capability_list_pt resolver_getCapabilityList(linked_list_pt list, const char * name) {
+    capability_list_pt capabilityList = NULL;
+    linked_list_iterator_pt iterator = linkedListIterator_create(list, 0);
+    while (linkedListIterator_hasNext(iterator)) {
+        capability_list_pt services = (capability_list_pt) linkedListIterator_next(iterator);
+        if (strcmp(services->serviceName, name) == 0) {
+            capabilityList = services;
+            break;
+        }
+    }
+    linkedListIterator_destroy(iterator);
+    return capabilityList;
+}
+
+linked_list_pt resolver_populateWireMap(hash_map_pt candidates, module_pt importer, linked_list_pt wireMap) {
+    linked_list_pt serviceWires;
+
+    if (candidates && importer && wireMap) {
+        linked_list_pt candSetList = NULL;
+        bool resolved = false;
+
+        if (module_isResolved(importer)) {
+            // already resolved
+            resolved = true;
+        }
+        if (!resolved) {
+            bool self = false;
+            linked_list_iterator_pt wit = linkedListIterator_create(wireMap, 0);
+            while (linkedListIterator_hasNext(wit)) {
+                importer_wires_pt iw = linkedListIterator_next(wit);
+                if (iw->importer == importer) {
+                    // Do not resolve yourself
+                    self = true;
+                    break;
+                }
+            }
+            linkedListIterator_destroy(wit);
+
+            if (!self) {
+                candSetList = (linked_list_pt) hashMap_get(candidates, importer);
+
+                if (linkedList_create(&serviceWires) == CELIX_SUCCESS) {
+//                    if (linkedList_create(&emptyWires) == CELIX_SUCCESS) {
+                    int candSetIdx = 0;
+
+                    // hashMap_put(wireMap, importer, emptyWires);
+
+                    const char *mname = NULL;
+                    module_getSymbolicName(importer, &mname);
+
+                    importer_wires_pt importerWires = malloc(sizeof(*importerWires));
+                    importerWires->importer = importer;
+                    importerWires->wires = NULL;
+                    linkedList_addElement(wireMap, importerWires);
+
+                    for (candSetIdx = 0; candSetIdx < linkedList_size(candSetList); candSetIdx++) {
+                        candidate_set_pt cs = (candidate_set_pt) linkedList_get(candSetList, candSetIdx);
+
+                        module_pt module = NULL;
+                        capability_getModule(((capability_pt) linkedList_get(cs->candidates, 0)), &module);
+                        if (importer != module) {
+                            wire_pt wire = NULL;
+                            wire_create(importer, cs->requirement, module, ((capability_pt) linkedList_get(cs->candidates, 0)), &wire);
+                            linkedList_addElement(serviceWires, wire);
+                        }
+
+                        wireMap = resolver_populateWireMap(candidates, module, wireMap);
+                    }
+
+                    importerWires->wires = serviceWires;
+                    // hashMap_put(wireMap, importer, serviceWires);
+//                    }
+                }
+            }
+        }
+    }
+
+    return wireMap;
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/framework/src/resolver.h
----------------------------------------------------------------------
diff --git a/framework/src/resolver.h b/framework/src/resolver.h
new file mode 100644
index 0000000..87440e9
--- /dev/null
+++ b/framework/src/resolver.h
@@ -0,0 +1,45 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+/*
+ * resolver.h
+ *
+ *  \date       Jul 13, 2010
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef RESOLVER_H_
+#define RESOLVER_H_
+
+#include "module.h"
+#include "wire.h"
+#include "hash_map.h"
+
+struct importer_wires {
+    module_pt importer;
+    linked_list_pt wires;
+};
+typedef struct importer_wires *importer_wires_pt;
+
+linked_list_pt resolver_resolve(module_pt root);
+void resolver_moduleResolved(module_pt module);
+void resolver_addModule(module_pt module);
+void resolver_removeModule(module_pt module);
+
+#endif /* RESOLVER_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/framework/src/service_reference.c
----------------------------------------------------------------------
diff --git a/framework/src/service_reference.c b/framework/src/service_reference.c
new file mode 100644
index 0000000..545426d
--- /dev/null
+++ b/framework/src/service_reference.c
@@ -0,0 +1,378 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+/*
+ * service_reference.c
+ *
+ *  \date       Jul 20, 2010
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <constants.h>
+#include <stdint.h>
+#include <utils.h>
+#include <assert.h>
+
+#include "service_reference.h"
+
+#include "service_reference_private.h"
+#include "service_registration_private.h"
+
+static void serviceReference_destroy(service_reference_pt);
+static void serviceReference_logWarningUsageCountBelowZero(service_reference_pt ref);
+
+celix_status_t serviceReference_create(registry_callback_t callback, bundle_pt referenceOwner, service_registration_pt registration,  service_reference_pt *out) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	service_reference_pt ref = calloc(1, sizeof(*ref));
+	if (!ref) {
+		status = CELIX_ENOMEM;
+	} else {
+        ref->callback = callback;
+		ref->referenceOwner = referenceOwner;
+		ref->registration = registration;
+        ref->service = NULL;
+        serviceRegistration_getBundle(registration, &ref->registrationBundle);
+		celixThreadRwlock_create(&ref->lock, NULL);
+		ref->refCount = 1;
+        ref->usageCount = 0;
+
+        serviceRegistration_retain(ref->registration);
+	}
+
+	if (status == CELIX_SUCCESS) {
+		*out = ref;
+	}
+
+    framework_logIfError(logger, status, NULL, "Cannot create service reference");
+
+	return status;
+}
+
+celix_status_t serviceReference_retain(service_reference_pt ref) {
+    celixThreadRwlock_writeLock(&ref->lock);
+    ref->refCount += 1;
+    celixThreadRwlock_unlock(&ref->lock);
+    return CELIX_SUCCESS;
+}
+
+celix_status_t serviceReference_release(service_reference_pt ref, bool *out) {
+    bool destroyed = false;
+    celixThreadRwlock_writeLock(&ref->lock);
+    assert(ref->refCount > 0);
+    ref->refCount -= 1;
+    if (ref->refCount == 0) {
+        if (ref->registration != NULL) {
+            serviceRegistration_release(ref->registration);
+        }
+        celixThreadRwlock_unlock(&ref->lock);
+        serviceReference_destroy(ref);
+        destroyed = true;
+    } else {
+        celixThreadRwlock_unlock(&ref->lock);
+    }
+
+    if (out) {
+        *out = destroyed;
+    }
+    return CELIX_SUCCESS;
+}
+
+celix_status_t serviceReference_increaseUsage(service_reference_pt ref, size_t *out) {
+    //fw_log(logger, OSGI_FRAMEWORK_LOG_DEBUG, "Destroying service reference %p\n", ref);
+    size_t local = 0;
+    celixThreadRwlock_writeLock(&ref->lock);
+    ref->usageCount += 1;
+    local = ref->usageCount;
+    celixThreadRwlock_unlock(&ref->lock);
+    if (out) {
+        *out = local;
+    }
+    return CELIX_SUCCESS;
+}
+
+celix_status_t serviceReference_decreaseUsage(service_reference_pt ref, size_t *out) {
+    celix_status_t status = CELIX_SUCCESS;
+    size_t localCount = 0;
+    celixThreadRwlock_writeLock(&ref->lock);
+    if (ref->usageCount == 0) {
+        serviceReference_logWarningUsageCountBelowZero(ref);
+        status = CELIX_BUNDLE_EXCEPTION;
+    } else {
+        ref->usageCount -= 1;
+    }
+    localCount = ref->usageCount;
+    celixThreadRwlock_unlock(&ref->lock);
+
+    if (out) {
+        *out = localCount;
+    }
+    return status;
+}
+
+static void serviceReference_logWarningUsageCountBelowZero(service_reference_pt ref __attribute__((unused))) {
+    fw_log(logger, OSGI_FRAMEWORK_LOG_WARNING, "Cannot decrease service usage count below 0\n");
+}
+
+
+celix_status_t serviceReference_getUsageCount(service_reference_pt ref, size_t *count) {
+    celix_status_t status = CELIX_SUCCESS;
+    celixThreadRwlock_readLock(&ref->lock);
+    *count = ref->usageCount;
+    celixThreadRwlock_unlock(&ref->lock);
+    return status;
+}
+
+celix_status_t serviceReference_getReferenceCount(service_reference_pt ref, size_t *count) {
+    celix_status_t status = CELIX_SUCCESS;
+    celixThreadRwlock_readLock(&ref->lock);
+    *count = ref->refCount;
+    celixThreadRwlock_unlock(&ref->lock);
+    return status;
+}
+
+celix_status_t serviceReference_getService(service_reference_pt ref, void **service) {
+    celix_status_t status = CELIX_SUCCESS;
+    celixThreadRwlock_readLock(&ref->lock);
+    /*NOTE the service argument should be 'const void**'
+      To ensure backwards compatability a cast is made instead.
+    */
+    *service = (const void**) ref->service;
+    celixThreadRwlock_unlock(&ref->lock);
+    return status;
+}
+
+celix_status_t serviceReference_setService(service_reference_pt ref, const void *service) {
+    celix_status_t status = CELIX_SUCCESS;
+    celixThreadRwlock_writeLock(&ref->lock);
+    ref->service = service;
+    celixThreadRwlock_unlock(&ref->lock);
+    return status;
+}
+
+static void serviceReference_destroy(service_reference_pt ref) {
+	assert(ref->refCount == 0);
+    celixThreadRwlock_destroy(&ref->lock);
+	ref->registration = NULL;
+	free(ref);
+}
+
+celix_status_t serviceReference_getBundle(service_reference_pt ref, bundle_pt *bundle) {
+    celix_status_t status = CELIX_SUCCESS;
+    celixThreadRwlock_readLock(&ref->lock);
+    if (ref->registration != NULL) {
+        *bundle = ref->registrationBundle;
+    }
+    celixThreadRwlock_unlock(&ref->lock);
+    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) {
+    if (ref != NULL) {
+        celixThreadRwlock_readLock(&ref->lock);
+        *out = ref->registration;
+        celixThreadRwlock_unlock(&ref->lock);
+        return CELIX_SUCCESS;
+    } else {
+        return CELIX_ILLEGAL_ARGUMENT;
+    }
+}
+
+celix_status_t serviceReference_getProperty(service_reference_pt ref, const char* key, const char** value) {
+    celix_status_t status = CELIX_SUCCESS;
+    properties_pt props = NULL;
+    celixThreadRwlock_readLock(&ref->lock);
+    if (ref->registration != NULL) {
+        status = serviceRegistration_getProperties(ref->registration, &props);
+        if (status == CELIX_SUCCESS) {
+            *value = (char*) properties_get(props, key);
+        }
+    } else {
+        *value = NULL;
+    }
+    celixThreadRwlock_unlock(&ref->lock);
+    return status;
+}
+
+FRAMEWORK_EXPORT celix_status_t serviceReference_getPropertyKeys(service_reference_pt ref, char **keys[], unsigned int *size) {
+    celix_status_t status = CELIX_SUCCESS;
+    properties_pt props = NULL;
+
+    celixThreadRwlock_readLock(&ref->lock);
+    serviceRegistration_getProperties(ref->registration, &props);
+    hash_map_iterator_pt it;
+    int i = 0;
+    int vsize = hashMap_size(props);
+    *size = (unsigned int)vsize;
+    *keys = malloc(vsize * sizeof(**keys));
+    it = hashMapIterator_create(props);
+    while (hashMapIterator_hasNext(it)) {
+        (*keys)[i] = hashMapIterator_nextKey(it);
+        i++;
+    }
+    hashMapIterator_destroy(it);
+    celixThreadRwlock_unlock(&ref->lock);
+    return status;
+}
+
+celix_status_t serviceReference_invalidate(service_reference_pt ref) {
+    assert(ref != NULL);
+    celix_status_t status = CELIX_SUCCESS;
+    service_registration_pt reg = NULL;
+    celixThreadRwlock_writeLock(&ref->lock);
+    reg = ref->registration;
+    ref->registration = NULL;
+    celixThreadRwlock_unlock(&ref->lock);
+
+    if (reg != NULL) {
+        serviceRegistration_release(reg);
+    }
+	return status;
+}
+
+celix_status_t serviceReference_isValid(service_reference_pt ref, bool *result) {
+    celixThreadRwlock_readLock(&ref->lock);
+    (*result) = ref->registration != NULL;
+    celixThreadRwlock_unlock(&ref->lock);
+    return CELIX_SUCCESS;
+}
+
+bool serviceReference_isAssignableTo(service_reference_pt reference __attribute__((unused)), bundle_pt requester __attribute__((unused)), const char* serviceName __attribute__((unused))) {
+	bool allow = true;
+
+	/*NOTE for now always true. It would be nice to be able to do somechecks if the services are really assignable.
+	 */
+
+	return allow;
+}
+
+celix_status_t serviceReference_equals(service_reference_pt reference, service_reference_pt compareTo, bool *equal) {
+    celix_status_t status = CELIX_SUCCESS;
+    if (reference != NULL && compareTo != NULL) {
+        service_registration_pt reg1;
+        service_registration_pt reg2;
+        serviceReference_getServiceRegistration(reference, &reg1);
+        serviceReference_getServiceRegistration(compareTo, &reg2);
+        *equal = (reg1 == reg2);
+    } else {
+        status = CELIX_ILLEGAL_ARGUMENT;
+        *equal = false;
+    }
+	return status;
+}
+
+int serviceReference_equals2(const void* reference1, const void* reference2) {
+	bool equal;
+	serviceReference_equals((service_reference_pt)reference1, (service_reference_pt)reference2, &equal);
+	return equal;
+}
+
+celix_status_t serviceReference_compareTo(service_reference_pt reference, service_reference_pt compareTo, int *compare) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	long id, other_id;
+	const char* id_str;
+    const char* other_id_str;
+	serviceReference_getProperty(reference, (char *) OSGI_FRAMEWORK_SERVICE_ID, &id_str);
+	serviceReference_getProperty(compareTo, (char *) OSGI_FRAMEWORK_SERVICE_ID, &other_id_str);
+
+	id = atol(id_str);
+	other_id = atol(other_id_str);
+
+
+	long rank, other_rank;
+	const char *rank_str;
+    const char* other_rank_str;
+	serviceReference_getProperty(reference, OSGI_FRAMEWORK_SERVICE_RANKING, &rank_str);
+	serviceReference_getProperty(compareTo, OSGI_FRAMEWORK_SERVICE_RANKING, &other_rank_str);
+
+	rank = rank_str == NULL ? 0 : atol(rank_str);
+	other_rank = other_rank_str == NULL ? 0 : atol(other_rank_str);
+
+    *compare = utils_compareServiceIdsAndRanking(id, rank, other_id, other_rank);
+
+	return status;
+}
+
+unsigned int serviceReference_hashCode(const void *referenceP) {
+    service_reference_pt ref = (service_reference_pt)referenceP;
+    bundle_pt bundle = NULL;
+    service_registration_pt reg = NULL;
+
+    if (ref != NULL) {
+        celixThreadRwlock_readLock(&ref->lock);
+        bundle = ref->registrationBundle;
+        reg = ref->registration;
+        celixThreadRwlock_unlock(&ref->lock);
+    }
+
+
+	int prime = 31;
+	int result = 1;
+	result = prime * result;
+
+	if (bundle != NULL && reg != NULL) {
+		intptr_t bundleA = (intptr_t) bundle;
+		intptr_t registrationA = (intptr_t) reg;
+
+		result += bundleA + registrationA;
+	}
+	return result;
+}
+
+
+celix_status_t serviceReference_getUsingBundles(service_reference_pt ref, array_list_pt *out) {
+    celix_status_t status = CELIX_SUCCESS;
+    service_registration_pt reg = NULL;
+    registry_callback_t callback;
+
+    callback.getUsingBundles = NULL;
+
+
+    celixThreadRwlock_readLock(&ref->lock);
+    reg = ref->registration;
+    if (reg != NULL) {
+        serviceRegistration_retain(reg);
+        callback.handle = ref->callback.handle;
+        callback.getUsingBundles = ref->callback.getUsingBundles;
+    }
+    celixThreadRwlock_unlock(&ref->lock);
+
+    if (reg != NULL) {
+        if (callback.getUsingBundles != NULL) {
+            status = callback.getUsingBundles(callback.handle, reg, out);
+        } else {
+            fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "getUsingBundles callback not set");
+            status = CELIX_BUNDLE_EXCEPTION;
+        }
+        serviceRegistration_release(reg);
+    }
+
+    return status;
+}
+

http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/framework/src/service_reference_private.h
----------------------------------------------------------------------
diff --git a/framework/src/service_reference_private.h b/framework/src/service_reference_private.h
new file mode 100644
index 0000000..d7fcac1
--- /dev/null
+++ b/framework/src/service_reference_private.h
@@ -0,0 +1,69 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+/*
+ * service_reference_private.h
+ *
+ *  \date       Feb 6, 2013
+ *  \author     <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright  Apache License, Version 2.0
+ */
+
+
+#ifndef SERVICE_REFERENCE_PRIVATE_H_
+#define SERVICE_REFERENCE_PRIVATE_H_
+
+#include "registry_callback_private.h"
+#include "service_reference.h"
+
+
+struct serviceReference {
+    registry_callback_t callback;
+	bundle_pt referenceOwner;
+	struct serviceRegistration * registration;
+    bundle_pt registrationBundle;
+    const void* service;
+
+	size_t refCount;
+    size_t usageCount;
+
+    celix_thread_rwlock_t lock;
+};
+
+celix_status_t serviceReference_create(registry_callback_t callback, bundle_pt referenceOwner, service_registration_pt registration, service_reference_pt *reference);
+
+celix_status_t serviceReference_retain(service_reference_pt ref);
+celix_status_t serviceReference_release(service_reference_pt ref, bool *destroyed);
+
+celix_status_t serviceReference_increaseUsage(service_reference_pt ref, size_t *updatedCount);
+celix_status_t serviceReference_decreaseUsage(service_reference_pt ref, size_t *updatedCount);
+
+celix_status_t serviceReference_invalidate(service_reference_pt reference);
+celix_status_t serviceReference_isValid(service_reference_pt reference, bool *result);
+
+celix_status_t serviceReference_getUsageCount(service_reference_pt reference, size_t *count);
+celix_status_t serviceReference_getReferenceCount(service_reference_pt reference, size_t *count);
+
+celix_status_t serviceReference_setService(service_reference_pt ref, const 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/a1c30887/framework/src/service_registration.c
----------------------------------------------------------------------
diff --git a/framework/src/service_registration.c b/framework/src/service_registration.c
new file mode 100644
index 0000000..5d23dbf
--- /dev/null
+++ b/framework/src/service_registration.c
@@ -0,0 +1,291 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+/*
+ * service_registration.c
+ *
+ *  \date       Aug 6, 2010
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "service_registration_private.h"
+#include "constants.h"
+
+static celix_status_t serviceRegistration_initializeProperties(service_registration_pt registration, properties_pt properties);
+static celix_status_t serviceRegistration_createInternal(registry_callback_t callback, bundle_pt bundle, const char* serviceName, unsigned long serviceId,
+        const void * serviceObject, properties_pt dictionary, bool isFactory, service_registration_pt *registration);
+static celix_status_t serviceRegistration_destroy(service_registration_pt registration);
+
+service_registration_pt serviceRegistration_create(registry_callback_t callback, bundle_pt bundle, const char* serviceName, unsigned long serviceId, const void * serviceObject, properties_pt dictionary) {
+    service_registration_pt registration = NULL;
+	serviceRegistration_createInternal(callback, bundle, serviceName, serviceId, serviceObject, dictionary, false, &registration);
+	return registration;
+}
+
+service_registration_pt serviceRegistration_createServiceFactory(registry_callback_t callback, bundle_pt bundle, const char* serviceName, unsigned long serviceId, const void * serviceObject, properties_pt dictionary) {
+    service_registration_pt registration = NULL;
+    serviceRegistration_createInternal(callback, bundle, serviceName, serviceId, serviceObject, dictionary, true, &registration);
+    return registration;
+}
+
+static celix_status_t serviceRegistration_createInternal(registry_callback_t callback, bundle_pt bundle, const char* serviceName, unsigned long serviceId,
+        const void * serviceObject, properties_pt dictionary, bool isFactory, service_registration_pt *out) {
+    celix_status_t status = CELIX_SUCCESS;
+
+	service_registration_pt  reg = calloc(1, sizeof(*reg));
+    if (reg) {
+        reg->callback = callback;
+        reg->services = NULL;
+        reg->nrOfServices = 0;
+		reg->isServiceFactory = isFactory;
+		reg->className = strndup(serviceName, 1024*10);
+		reg->bundle = bundle;
+		reg->refCount = 1;
+
+		reg->serviceId = serviceId;
+	reg->svcObj = serviceObject;
+		if (isFactory) {
+			reg->serviceFactory = (service_factory_pt) reg->svcObj;
+		} else {
+			reg->serviceFactory = NULL;
+		}
+
+		reg->isUnregistering = false;
+		celixThreadRwlock_create(&reg->lock, NULL);
+
+		celixThreadRwlock_writeLock(&reg->lock);
+		serviceRegistration_initializeProperties(reg, dictionary);
+		celixThreadRwlock_unlock(&reg->lock);
+
+	} else {
+		status = CELIX_ENOMEM;
+	}
+
+	if (status == CELIX_SUCCESS) {
+		*out = reg;
+	}
+
+	return status;
+}
+
+void serviceRegistration_retain(service_registration_pt registration) {
+	celixThreadRwlock_writeLock(&registration->lock);
+	registration->refCount += 1;
+    celixThreadRwlock_unlock(&registration->lock);
+}
+
+void serviceRegistration_release(service_registration_pt registration) {
+    celixThreadRwlock_writeLock(&registration->lock);
+    assert(registration->refCount > 0);
+	registration->refCount -= 1;
+	if (registration->refCount == 0) {
+		serviceRegistration_destroy(registration);
+	} else {
+        celixThreadRwlock_unlock(&registration->lock);
+	}
+}
+
+static celix_status_t serviceRegistration_destroy(service_registration_pt registration) {
+	//fw_log(logger, OSGI_FRAMEWORK_LOG_DEBUG, "Destroying service registration %p\n", registration);
+    free(registration->className);
+	registration->className = NULL;
+
+    registration->callback.unregister = NULL;
+
+	properties_destroy(registration->properties);
+	celixThreadRwlock_unlock(&registration->lock);
+    celixThreadRwlock_destroy(&registration->lock);
+	free(registration);
+
+	return CELIX_SUCCESS;
+}
+
+static celix_status_t serviceRegistration_initializeProperties(service_registration_pt registration, properties_pt dictionary) {
+    char sId[32];
+
+	if (dictionary == NULL) {
+		dictionary = properties_create();
+	}
+
+
+	snprintf(sId, 32, "%lu", registration->serviceId);
+	properties_set(dictionary, (char *) OSGI_FRAMEWORK_SERVICE_ID, sId);
+
+	if (properties_get(dictionary, (char *) OSGI_FRAMEWORK_OBJECTCLASS) == NULL) {
+		properties_set(dictionary, (char *) OSGI_FRAMEWORK_OBJECTCLASS, registration->className);
+	}
+
+	registration->properties = dictionary;
+
+	return CELIX_SUCCESS;
+}
+
+void serviceRegistration_invalidate(service_registration_pt registration) {
+    celixThreadRwlock_writeLock(&registration->lock);
+    registration->svcObj = NULL;
+    celixThreadRwlock_unlock(&registration->lock);
+}
+
+bool serviceRegistration_isValid(service_registration_pt registration) {
+    bool isValid;
+    if (registration != NULL) {
+        celixThreadRwlock_readLock(&registration->lock);
+        isValid = registration->svcObj != NULL;
+        celixThreadRwlock_unlock(&registration->lock);
+    } else {
+        isValid = false;
+    }
+    return isValid;
+}
+
+celix_status_t serviceRegistration_unregister(service_registration_pt registration) {
+	celix_status_t status = CELIX_SUCCESS;
+
+    bool notValidOrUnregistering;
+    celixThreadRwlock_readLock(&registration->lock);
+    notValidOrUnregistering = !serviceRegistration_isValid(registration) || registration->isUnregistering;
+    celixThreadRwlock_unlock(&registration->lock);
+
+    registry_callback_t callback;
+    callback.unregister = NULL;
+    bundle_pt bundle = NULL;
+
+	if (notValidOrUnregistering) {
+		status = CELIX_ILLEGAL_STATE;
+	} else {
+        celixThreadRwlock_writeLock(&registration->lock);
+        registration->isUnregistering = true;
+        bundle = registration->bundle;
+        callback = registration->callback;
+        celixThreadRwlock_unlock(&registration->lock);
+    }
+
+	if (status == CELIX_SUCCESS && callback.unregister != NULL) {
+        callback.unregister(callback.handle, bundle, registration);
+	}
+
+	framework_logIfError(logger, status, NULL, "Cannot unregister service registration");
+
+	return status;
+}
+
+celix_status_t serviceRegistration_getService(service_registration_pt registration, bundle_pt bundle, const void** service) {
+	int status = CELIX_SUCCESS;
+    celixThreadRwlock_readLock(&registration->lock);
+    if (registration->isServiceFactory) {
+        service_factory_pt factory = (void*) registration->serviceFactory;
+        /*NOTE the service argument of the service_factory should be const void**.
+          To ensure backwards compatability a cast is made instead.
+        */
+        status = factory->getService(factory->handle, bundle, registration, (void**) service);
+    } else {
+        (*service) = registration->svcObj;
+    }
+    celixThreadRwlock_unlock(&registration->lock);
+    return status;
+}
+
+celix_status_t serviceRegistration_ungetService(service_registration_pt registration, bundle_pt bundle, const void** service) {
+    celixThreadRwlock_readLock(&registration->lock);
+    if (registration->isServiceFactory) {
+        service_factory_pt factory = (void*) registration->serviceFactory;
+        /*NOTE the service argument of the service_factory should be const void**.
+          To ensure backwards compatability a cast is made instead.
+        */
+        factory->ungetService(factory->handle, bundle, registration, (void**) service);
+    }
+    celixThreadRwlock_unlock(&registration->lock);
+    return CELIX_SUCCESS;
+}
+
+celix_status_t serviceRegistration_getProperties(service_registration_pt registration, properties_pt *properties) {
+	celix_status_t status = CELIX_SUCCESS;
+
+    if (registration != NULL) {
+        celixThreadRwlock_readLock(&registration->lock);
+        *properties = registration->properties;
+        celixThreadRwlock_unlock(&registration->lock);
+     } else {
+          status = CELIX_ILLEGAL_ARGUMENT;
+     }
+
+    framework_logIfError(logger, status, NULL, "Cannot get registration properties");
+
+    return status;
+}
+
+celix_status_t serviceRegistration_setProperties(service_registration_pt registration, properties_pt properties) {
+    celix_status_t status;
+
+    properties_pt oldProperties = NULL;
+    registry_callback_t callback;
+
+    celixThreadRwlock_writeLock(&registration->lock);
+    oldProperties = registration->properties;
+    status = serviceRegistration_initializeProperties(registration, properties);
+    callback = registration->callback;
+    celixThreadRwlock_unlock(&registration->lock);
+
+    if (status == CELIX_SUCCESS && callback.modified != NULL) {
+        callback.modified(callback.handle, registration, oldProperties);
+    }
+
+	return status;
+}
+
+
+celix_status_t serviceRegistration_getBundle(service_registration_pt registration, bundle_pt *bundle) {
+    celix_status_t status = CELIX_SUCCESS;
+    if (registration == NULL) {
+        return CELIX_ILLEGAL_ARGUMENT;
+    }
+
+    if (registration != NULL && *bundle == NULL) {
+        celixThreadRwlock_readLock(&registration->lock);
+        *bundle = registration->bundle;
+        celixThreadRwlock_unlock(&registration->lock);
+	} else {
+		status = CELIX_ILLEGAL_ARGUMENT;
+	}
+
+    framework_logIfError(logger, status, NULL, "Cannot get bundle");
+
+	return status;
+}
+
+celix_status_t serviceRegistration_getServiceName(service_registration_pt registration, const char **serviceName) {
+	celix_status_t status = CELIX_SUCCESS;
+
+    if (registration != NULL && *serviceName == NULL) {
+        celixThreadRwlock_readLock(&registration->lock);
+        *serviceName = registration->className;
+        celixThreadRwlock_unlock(&registration->lock);
+	} else {
+        status = CELIX_ILLEGAL_ARGUMENT;
+    }
+
+
+    framework_logIfError(logger, status, NULL, "Cannot get service name");
+
+	return status;
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/framework/src/service_registration_private.h
----------------------------------------------------------------------
diff --git a/framework/src/service_registration_private.h b/framework/src/service_registration_private.h
new file mode 100644
index 0000000..ca0cb67
--- /dev/null
+++ b/framework/src/service_registration_private.h
@@ -0,0 +1,71 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+/*
+ * service_registration_private.h
+ *
+ *  \date       Feb 11, 2013
+ *  \author     <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright  Apache License, Version 2.0
+ */
+
+
+#ifndef SERVICE_REGISTRATION_PRIVATE_H_
+#define SERVICE_REGISTRATION_PRIVATE_H_
+
+#include "registry_callback_private.h"
+#include "service_registration.h"
+
+struct serviceRegistration {
+    registry_callback_t callback;
+
+	char * className;
+	bundle_pt bundle;
+	properties_pt properties;
+	const void * svcObj;
+	unsigned long serviceId;
+
+	bool isUnregistering;
+
+	bool isServiceFactory;
+	const void *serviceFactory;
+
+	struct service *services;
+	int nrOfServices;
+
+	size_t refCount; //protected by mutex
+
+	celix_thread_rwlock_t lock;
+};
+
+service_registration_pt serviceRegistration_create(registry_callback_t callback, bundle_pt bundle, const char* serviceName, unsigned long serviceId, const void * serviceObject, properties_pt dictionary);
+service_registration_pt serviceRegistration_createServiceFactory(registry_callback_t callback, bundle_pt bundle, const char* serviceName, unsigned long serviceId, const void * serviceObject, properties_pt dictionary);
+
+void serviceRegistration_retain(service_registration_pt registration);
+void serviceRegistration_release(service_registration_pt registration);
+
+bool serviceRegistration_isValid(service_registration_pt registration);
+void serviceRegistration_invalidate(service_registration_pt registration);
+
+celix_status_t serviceRegistration_getService(service_registration_pt registration, bundle_pt bundle, const void **service);
+celix_status_t serviceRegistration_ungetService(service_registration_pt registration, bundle_pt bundle, const void **service);
+
+celix_status_t serviceRegistration_getBundle(service_registration_pt registration, bundle_pt *bundle);
+celix_status_t serviceRegistration_getServiceName(service_registration_pt registration, const char **serviceName);
+
+#endif /* SERVICE_REGISTRATION_PRIVATE_H_ */

http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/framework/src/service_registry.c
----------------------------------------------------------------------
diff --git a/framework/src/service_registry.c b/framework/src/service_registry.c
new file mode 100644
index 0000000..d27cc32
--- /dev/null
+++ b/framework/src/service_registry.c
@@ -0,0 +1,800 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+/*
+ * service_registry.c
+ *
+ *  \date       Aug 6, 2010
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "service_registry_private.h"
+#include "service_registration_private.h"
+#include "listener_hook_service.h"
+#include "constants.h"
+#include "service_reference_private.h"
+#include "framework_private.h"
+
+#ifdef DEBUG
+#define CHECK_DELETED_REFERENCES true
+#else
+#define CHECK_DELETED_REFERENCES false
+#endif
+
+static celix_status_t serviceRegistry_registerServiceInternal(service_registry_pt registry, bundle_pt bundle, const char* serviceName, const void * serviceObject, properties_pt dictionary, bool isFactory, service_registration_pt *registration);
+static celix_status_t serviceRegistry_addHooks(service_registry_pt registry, const char* serviceName, const void *serviceObject, service_registration_pt registration);
+static celix_status_t serviceRegistry_removeHook(service_registry_pt registry, service_registration_pt registration);
+static void serviceRegistry_logWarningServiceReferenceUsageCount(service_registry_pt registry, bundle_pt bundle, service_reference_pt ref, size_t usageCount, size_t refCount);
+static void serviceRegistry_logWarningServiceRegistration(service_registry_pt registry, service_registration_pt reg);
+static celix_status_t serviceRegistry_checkReference(service_registry_pt registry, service_reference_pt ref,
+                                                     reference_status_t *refStatus);
+static void serviceRegistry_logIllegalReference(service_registry_pt registry, service_reference_pt reference,
+                                                   reference_status_t refStatus);
+static celix_status_t serviceRegistry_setReferenceStatus(service_registry_pt registry, service_reference_pt reference,
+                                                  bool deleted);
+static celix_status_t serviceRegistry_getUsingBundles(service_registry_pt registry, service_registration_pt reg, array_list_pt *bundles);
+static celix_status_t serviceRegistry_getServiceReference_internal(service_registry_pt registry, bundle_pt owner, service_registration_pt registration, service_reference_pt *out);
+
+celix_status_t serviceRegistry_create(framework_pt framework, serviceChanged_function_pt serviceChanged, service_registry_pt *out) {
+	celix_status_t status;
+
+	service_registry_pt reg = calloc(1, sizeof(*reg));
+	if (reg == NULL) {
+		status = CELIX_ENOMEM;
+	} else {
+
+        reg->callback.handle = reg;
+        reg->callback.getUsingBundles = (void *)serviceRegistry_getUsingBundles;
+        reg->callback.unregister = (void *) serviceRegistry_unregisterService;
+        reg->callback.modified = (void *) serviceRegistry_servicePropertiesModified;
+
+        reg->serviceChanged = serviceChanged;
+		reg->serviceRegistrations = hashMap_create(NULL, NULL, NULL, NULL);
+		reg->framework = framework;
+		reg->currentServiceId = 1UL;
+		reg->serviceReferences = hashMap_create(NULL, NULL, NULL, NULL);
+
+        reg->checkDeletedReferences = CHECK_DELETED_REFERENCES;
+        reg->deletedServiceReferences = hashMap_create(NULL, NULL, NULL, NULL);
+
+		arrayList_create(&reg->listenerHooks);
+
+		status = celixThreadRwlock_create(&reg->lock, NULL);
+	}
+
+	if (status == CELIX_SUCCESS) {
+		*out = reg;
+	} else {
+		framework_logIfError(logger, status, NULL, "Cannot create service registry");
+	}
+
+	return status;
+}
+
+celix_status_t serviceRegistry_destroy(service_registry_pt registry) {
+    celixThreadRwlock_writeLock(&registry->lock);
+
+    //destroy service registration map
+    int size = hashMap_size(registry->serviceRegistrations);
+    assert(size == 0);
+    hashMap_destroy(registry->serviceRegistrations, false, false);
+
+    //destroy service references (double) map);
+    //FIXME. The framework bundle does not (yet) call clearReferences, as result the size could be > 0 for test code.
+    //size = hashMap_size(registry->serviceReferences);
+    //assert(size == 0);
+    hashMap_destroy(registry->serviceReferences, false, false);
+
+    //destroy listener hooks
+    size = arrayList_size(registry->listenerHooks);
+    if (size == 0)
+    	arrayList_destroy(registry->listenerHooks);
+
+    hashMap_destroy(registry->deletedServiceReferences, false, false);
+
+    free(registry);
+
+    return CELIX_SUCCESS;
+}
+
+celix_status_t serviceRegistry_getRegisteredServices(service_registry_pt registry, bundle_pt bundle, array_list_pt *services) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	celixThreadRwlock_writeLock(&registry->lock);
+
+	array_list_pt regs = (array_list_pt) hashMap_get(registry->serviceRegistrations, bundle);
+	if (regs != NULL) {
+		unsigned int i;
+		arrayList_create(services);
+		
+		for (i = 0; i < arrayList_size(regs); i++) {
+			service_registration_pt reg = arrayList_get(regs, i);
+			if (serviceRegistration_isValid(reg)) {
+				service_reference_pt reference = NULL;
+				status = serviceRegistry_getServiceReference_internal(registry, bundle, reg, &reference);
+				if (status == CELIX_SUCCESS) {
+					arrayList_add(*services, reference);
+				}
+			}
+		}
+	}
+
+	celixThreadRwlock_unlock(&registry->lock);
+
+	framework_logIfError(logger, status, NULL, "Cannot get registered services");
+
+	return status;
+}
+
+celix_status_t serviceRegistry_registerService(service_registry_pt registry, bundle_pt bundle, const char* serviceName, const void* serviceObject, properties_pt dictionary, service_registration_pt *registration) {
+    return serviceRegistry_registerServiceInternal(registry, bundle, serviceName, serviceObject, dictionary, false, registration);
+}
+
+celix_status_t serviceRegistry_registerServiceFactory(service_registry_pt registry, bundle_pt bundle, const char* serviceName, service_factory_pt factory, properties_pt dictionary, service_registration_pt *registration) {
+    return serviceRegistry_registerServiceInternal(registry, bundle, serviceName, (const void *) factory, dictionary, true, registration);
+}
+
+static celix_status_t serviceRegistry_registerServiceInternal(service_registry_pt registry, bundle_pt bundle, const char* serviceName, const void* serviceObject, properties_pt dictionary, bool isFactory, service_registration_pt *registration) {
+	array_list_pt regs;
+
+	if (isFactory) {
+	    *registration = serviceRegistration_createServiceFactory(registry->callback, bundle, serviceName, ++registry->currentServiceId, serviceObject, dictionary);
+	} else {
+	    *registration = serviceRegistration_create(registry->callback, bundle, serviceName, ++registry->currentServiceId, serviceObject, dictionary);
+	}
+
+    //long id;
+    //bundle_getBundleId(bundle, &id);
+    //fprintf(stderr, "REG: Registering service '%s' for bundle id %li with reg pointer %p\n", serviceName, id, *registration);
+
+
+    serviceRegistry_addHooks(registry, serviceName, serviceObject, *registration);
+
+	celixThreadRwlock_writeLock(&registry->lock);
+	regs = (array_list_pt) hashMap_get(registry->serviceRegistrations, bundle);
+	if (regs == NULL) {
+		regs = NULL;
+		arrayList_create(&regs);
+        hashMap_put(registry->serviceRegistrations, bundle, regs);
+    }
+	arrayList_add(regs, *registration);
+	celixThreadRwlock_unlock(&registry->lock);
+
+	if (registry->serviceChanged != NULL) {
+		registry->serviceChanged(registry->framework, OSGI_FRAMEWORK_SERVICE_EVENT_REGISTERED, *registration, NULL);
+	}
+
+	return CELIX_SUCCESS;
+}
+
+celix_status_t serviceRegistry_unregisterService(service_registry_pt registry, bundle_pt bundle, service_registration_pt registration) {
+	// array_list_t clients;
+	array_list_pt regs;
+
+    //fprintf(stderr, "REG: Unregistering service registration with pointer %p\n", registration);
+
+	serviceRegistry_removeHook(registry, registration);
+
+	celixThreadRwlock_writeLock(&registry->lock);
+	regs = (array_list_pt) hashMap_get(registry->serviceRegistrations, bundle);
+	if (regs != NULL) {
+		arrayList_removeElement(regs, registration);
+        int size = arrayList_size(regs);
+        if (size == 0) {
+            arrayList_destroy(regs);
+            hashMap_remove(registry->serviceRegistrations, bundle);
+        }
+	}
+	celixThreadRwlock_unlock(&registry->lock);
+
+	if (registry->serviceChanged != NULL) {
+		registry->serviceChanged(registry->framework, OSGI_FRAMEWORK_SERVICE_EVENT_UNREGISTERING, registration, NULL);
+	}
+
+
+	celixThreadRwlock_readLock(&registry->lock);
+    //invalidate service references
+    hash_map_iterator_pt iter = hashMapIterator_create(registry->serviceReferences);
+    while (hashMapIterator_hasNext(iter)) {
+        hash_map_pt refsMap = hashMapIterator_nextValue(iter);
+        service_reference_pt ref = refsMap != NULL ?
+                                   hashMap_get(refsMap, (void*)registration->serviceId) : NULL;
+        if (ref != NULL) {
+            serviceReference_invalidate(ref);
+        }
+    }
+    hashMapIterator_destroy(iter);
+	celixThreadRwlock_unlock(&registry->lock);
+
+	serviceRegistration_invalidate(registration);
+    serviceRegistration_release(registration);
+
+	return CELIX_SUCCESS;
+}
+
+celix_status_t serviceRegistry_clearServiceRegistrations(service_registry_pt registry, bundle_pt bundle) {
+    celix_status_t status = CELIX_SUCCESS;
+    array_list_pt registrations = NULL;
+    bool registrationsLeft;
+
+    celixThreadRwlock_writeLock(&registry->lock);
+    registrations = hashMap_get(registry->serviceRegistrations, bundle);
+    registrationsLeft = (registrations != NULL);
+    if (registrationsLeft) {
+        registrationsLeft = (arrayList_size(registrations) > 0);
+    }
+    celixThreadRwlock_unlock(&registry->lock);
+
+    while (registrationsLeft) {
+        service_registration_pt reg = arrayList_get(registrations, 0);
+
+        serviceRegistry_logWarningServiceRegistration(registry, reg);
+
+        if (serviceRegistration_isValid(reg)) {
+            serviceRegistration_unregister(reg);
+        }
+        else {
+            arrayList_remove(registrations, 0);
+        }
+
+        // not removed by last unregister call?
+        celixThreadRwlock_writeLock(&registry->lock);
+        registrations = hashMap_get(registry->serviceRegistrations, bundle);
+        registrationsLeft = (registrations != NULL);
+        if (registrationsLeft) {
+            registrationsLeft = (arrayList_size(registrations) > 0);
+        }
+        celixThreadRwlock_unlock(&registry->lock);
+    }
+
+    return status;
+}
+
+static void serviceRegistry_logWarningServiceRegistration(service_registry_pt registry __attribute__((unused)), service_registration_pt reg) {
+    const char *servName = NULL;
+    serviceRegistration_getServiceName(reg, &servName);
+    fw_log(logger, OSGI_FRAMEWORK_LOG_WARNING, "Dangling service registration for service %s. Look for missing serviceRegistration_unregister calls.", servName);
+}
+
+celix_status_t serviceRegistry_getServiceReference(service_registry_pt registry, bundle_pt owner,
+                                                   service_registration_pt registration, service_reference_pt *out) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	if(celixThreadRwlock_writeLock(&registry->lock) == CELIX_SUCCESS) {
+	    status = serviceRegistry_getServiceReference_internal(registry, owner, registration, out);
+	    celixThreadRwlock_unlock(&registry->lock);
+	}
+
+	return status;
+}
+
+static celix_status_t serviceRegistry_getServiceReference_internal(service_registry_pt registry, bundle_pt owner,
+                                                   service_registration_pt registration, service_reference_pt *out) {
+	//only call after locked registry RWlock
+	celix_status_t status = CELIX_SUCCESS;
+	bundle_pt bundle = NULL;
+    service_reference_pt ref = NULL;
+    hash_map_pt references = NULL;
+
+    references = hashMap_get(registry->serviceReferences, owner);
+    if (references == NULL) {
+        references = hashMap_create(NULL, NULL, NULL, NULL);
+        hashMap_put(registry->serviceReferences, owner, references);
+	}
+
+    ref = hashMap_get(references, (void*)registration->serviceId);
+
+    if (ref == NULL) {
+        status = serviceRegistration_getBundle(registration, &bundle);
+        if (status == CELIX_SUCCESS) {
+            status = serviceReference_create(registry->callback, owner, registration, &ref);
+        }
+        if (status == CELIX_SUCCESS) {
+            hashMap_put(references, (void*)registration->serviceId, ref);
+            hashMap_put(registry->deletedServiceReferences, ref, (void *)false);
+        }
+    } else {
+        serviceReference_retain(ref);
+    }
+
+    if (status == CELIX_SUCCESS) {
+        *out = ref;
+    }
+
+	framework_logIfError(logger, status, NULL, "Cannot create service reference");
+
+
+	return status;
+}
+
+celix_status_t serviceRegistry_getServiceReferences(service_registry_pt registry, bundle_pt owner, const char *serviceName, filter_pt filter, array_list_pt *out) {
+	celix_status_t status;
+	hash_map_iterator_pt iterator;
+    array_list_pt references = NULL;
+	array_list_pt matchingRegistrations = NULL;
+    bool matchResult;
+
+    status = arrayList_create(&references);
+    status = CELIX_DO_IF(status, arrayList_create(&matchingRegistrations));
+
+    celixThreadRwlock_readLock(&registry->lock);
+	iterator = hashMapIterator_create(registry->serviceRegistrations);
+	while (status == CELIX_SUCCESS && hashMapIterator_hasNext(iterator)) {
+		array_list_pt regs = (array_list_pt) hashMapIterator_nextValue(iterator);
+		unsigned int regIdx;
+		for (regIdx = 0; (regs != NULL) && regIdx < arrayList_size(regs); regIdx++) {
+			service_registration_pt registration = (service_registration_pt) arrayList_get(regs, regIdx);
+			properties_pt props = NULL;
+
+			status = serviceRegistration_getProperties(registration, &props);
+			if (status == CELIX_SUCCESS) {
+				bool matched = false;
+				matchResult = false;
+				if (filter != NULL) {
+					filter_match(filter, props, &matchResult);
+				}
+				if ((serviceName == NULL) && ((filter == NULL) || matchResult)) {
+					matched = true;
+				} else if (serviceName != NULL) {
+					const char *className = NULL;
+					matchResult = false;
+					serviceRegistration_getServiceName(registration, &className);
+					if (filter != NULL) {
+						filter_match(filter, props, &matchResult);
+					}
+					if ((strcmp(className, serviceName) == 0) && ((filter == NULL) || matchResult)) {
+						matched = true;
+					}
+				}
+				if (matched) {
+					if (serviceRegistration_isValid(registration)) {
+                        serviceRegistration_retain(registration);
+                        arrayList_add(matchingRegistrations, registration);
+					}
+				}
+			}
+		}
+	}
+    celixThreadRwlock_unlock(&registry->lock);
+	hashMapIterator_destroy(iterator);
+
+    if (status == CELIX_SUCCESS) {
+        unsigned int i;
+        unsigned int size = arrayList_size(matchingRegistrations);
+
+        for (i = 0; i < size; i += 1) {
+            service_registration_pt reg = arrayList_get(matchingRegistrations, i);
+            service_reference_pt reference = NULL;
+            celix_status_t subStatus = serviceRegistry_getServiceReference(registry, owner, reg, &reference);
+            if (subStatus == CELIX_SUCCESS) {
+                arrayList_add(references, reference);
+            } else {
+                status = CELIX_BUNDLE_EXCEPTION;
+            }
+            serviceRegistration_release(reg);
+        }
+    }
+
+    if(matchingRegistrations != NULL){
+    	arrayList_destroy(matchingRegistrations);
+    }
+
+    if (status == CELIX_SUCCESS) {
+        *out = references;
+    } else {
+        //TODO ungetServiceRefs
+        arrayList_destroy(references);
+        framework_logIfError(logger, status, NULL, "Cannot get service references");
+    }
+
+	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 (refStatus == 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;
+    bool destroyed = false;
+    size_t count = 0;
+    reference_status_t refStatus;
+
+    celixThreadRwlock_writeLock(&registry->lock);
+    serviceRegistry_checkReference(registry, reference, &refStatus);
+    if (refStatus == REF_ACTIVE) {
+        serviceReference_getUsageCount(reference, &count);
+        serviceReference_release(reference, &destroyed);
+        if (destroyed) {
+
+            if (count > 0) {
+                serviceRegistry_logWarningServiceReferenceUsageCount(registry, bundle, reference, count, 0);
+            }
+
+            hash_map_pt refsMap = hashMap_get(registry->serviceReferences, bundle);
+
+            unsigned long refId = 0UL;
+            service_reference_pt ref = NULL;
+            hash_map_iterator_pt iter = hashMapIterator_create(refsMap);
+            while (hashMapIterator_hasNext(iter)) {
+                hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
+                refId = (unsigned long)hashMapEntry_getKey(entry); //note could be invalid e.g. freed
+                ref = hashMapEntry_getValue(entry);
+
+                if (ref == reference) {
+                    break;
+                } else {
+                    ref = NULL;
+                    refId = 0UL;
+                }
+            }
+            hashMapIterator_destroy(iter);
+
+            if (ref != NULL) {
+                hashMap_remove(refsMap, (void*)refId);
+                int size = hashMap_size(refsMap);
+                if (size == 0) {
+                    hashMap_destroy(refsMap, false, false);
+                    hashMap_remove(registry->serviceReferences, bundle);
+                }
+                serviceRegistry_setReferenceStatus(registry, reference, true);
+            } else {
+                fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Cannot find reference %p in serviceReferences map",
+                       reference);
+            }
+        }
+    } else {
+        serviceRegistry_logIllegalReference(registry, reference, refStatus);
+    }
+    celixThreadRwlock_unlock(&registry->lock);
+
+    return status;
+}
+
+static celix_status_t serviceRegistry_setReferenceStatus(service_registry_pt registry, service_reference_pt reference,
+                                                  bool deleted) {
+    //precondition write locked on registry->lock
+    if (registry->checkDeletedReferences) {
+        hashMap_put(registry->deletedServiceReferences, reference, (void *) deleted);
+    }
+    return CELIX_SUCCESS;
+}
+
+static void serviceRegistry_logIllegalReference(service_registry_pt registry __attribute__((unused)), service_reference_pt reference,
+                                                   reference_status_t refStatus) {
+    fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR,
+           "Error handling service reference %p, status is %i",reference, refStatus);
+}
+
+static celix_status_t serviceRegistry_checkReference(service_registry_pt registry, service_reference_pt ref,
+                                              reference_status_t *out) {
+    //precondition read or write locked on registry->lock
+    celix_status_t status = CELIX_SUCCESS;
+
+    if (registry->checkDeletedReferences) {
+        reference_status_t refStatus = REF_UNKNOWN;
+
+        if (hashMap_containsKey(registry->deletedServiceReferences, ref)) {
+            bool deleted = (bool) hashMap_get(registry->deletedServiceReferences, ref);
+            refStatus = deleted ? REF_DELETED : REF_ACTIVE;
+        }
+
+        *out = refStatus;
+    } else {
+        *out = REF_ACTIVE;
+    }
+
+    return status;
+}
+
+static void serviceRegistry_logWarningServiceReferenceUsageCount(service_registry_pt registry __attribute__((unused)), bundle_pt bundle, service_reference_pt ref, size_t usageCount, size_t refCount) {
+    if (usageCount > 0) {
+        fw_log(logger, OSGI_FRAMEWORK_LOG_WARNING, "Service Reference destroyed with usage count is %zu, expected 0. Look for missing bundleContext_ungetService calls.", usageCount);
+    }
+    if (refCount > 0) {
+        fw_log(logger, OSGI_FRAMEWORK_LOG_WARNING, "Dangling service reference. Reference count is %zu, expected 1.  Look for missing bundleContext_ungetServiceReference calls.", refCount);
+    }
+
+    if(usageCount > 0 || refCount > 0) {
+        module_pt module_ptr = NULL;
+        bundle_getCurrentModule(bundle, &module_ptr);
+        const char* bundle_name = NULL;
+        module_getSymbolicName(module_ptr, &bundle_name);
+
+        const char* service_name = "unknown";
+        const char* bundle_provider_name = "unknown";
+        if (refCount > 0 && ref != NULL) {
+            serviceReference_getProperty(ref, OSGI_FRAMEWORK_OBJECTCLASS, &service_name);
+            service_registration_pt reg = NULL;
+            bundle_pt bundle = NULL;
+            module_pt mod = NULL;
+            serviceReference_getServiceRegistration(ref, &reg);
+            serviceRegistration_getBundle(reg, &bundle);
+            bundle_getCurrentModule(bundle, &mod);
+            module_getSymbolicName(mod, &bundle_provider_name);
+        }
+
+        fw_log(logger, OSGI_FRAMEWORK_LOG_WARNING, "Previous Dangling service reference warnings caused by bundle '%s', for service '%s', provided by bundle '%s'", bundle_name, service_name, bundle_provider_name);
+    }
+}
+
+
+celix_status_t serviceRegistry_clearReferencesFor(service_registry_pt registry, bundle_pt bundle) {
+    celix_status_t status = CELIX_SUCCESS;
+
+    celixThreadRwlock_writeLock(&registry->lock);
+
+    hash_map_pt refsMap = hashMap_remove(registry->serviceReferences, bundle);
+    if (refsMap != NULL) {
+        hash_map_iterator_pt iter = hashMapIterator_create(refsMap);
+        while (hashMapIterator_hasNext(iter)) {
+            service_reference_pt ref = hashMapIterator_nextValue(iter);
+            size_t refCount;
+            size_t usageCount;
+
+            serviceReference_getUsageCount(ref, &usageCount);
+            serviceReference_getReferenceCount(ref, &refCount);
+            serviceRegistry_logWarningServiceReferenceUsageCount(registry, bundle, ref, usageCount, refCount);
+
+            while (usageCount > 0) {
+                serviceReference_decreaseUsage(ref, &usageCount);
+            }
+
+            bool destroyed = false;
+            while (!destroyed) {
+                serviceReference_release(ref, &destroyed);
+            }
+            serviceRegistry_setReferenceStatus(registry, ref, true);
+
+        }
+        hashMapIterator_destroy(iter);
+        hashMap_destroy(refsMap, false, false);
+    }
+
+    celixThreadRwlock_unlock(&registry->lock);
+
+    return status;
+}
+
+
+celix_status_t serviceRegistry_getServicesInUse(service_registry_pt registry, bundle_pt bundle, array_list_pt *out) {
+
+    array_list_pt result = NULL;
+    arrayList_create(&result);
+
+    //LOCK
+    celixThreadRwlock_readLock(&registry->lock);
+
+    hash_map_pt refsMap = hashMap_get(registry->serviceReferences, bundle);
+
+    if(refsMap) {
+        hash_map_iterator_pt iter = hashMapIterator_create(refsMap);
+        while (hashMapIterator_hasNext(iter)) {
+            service_reference_pt ref = hashMapIterator_nextValue(iter);
+            arrayList_add(result, ref);
+        }
+        hashMapIterator_destroy(iter);
+    }
+
+    //UNLOCK
+    celixThreadRwlock_unlock(&registry->lock);
+
+    *out = result;
+
+	return CELIX_SUCCESS;
+}
+
+celix_status_t serviceRegistry_getService(service_registry_pt registry, bundle_pt bundle, service_reference_pt reference, const void **out) {
+	celix_status_t status = CELIX_SUCCESS;
+	service_registration_pt registration = NULL;
+    size_t count = 0;
+    const void *service = NULL;
+    reference_status_t refStatus;
+
+
+
+    celixThreadRwlock_readLock(&registry->lock);
+    serviceRegistry_checkReference(registry, reference, &refStatus);
+    if (refStatus == REF_ACTIVE) {
+        serviceReference_getServiceRegistration(reference, &registration);
+
+        if (serviceRegistration_isValid(registration)) {
+            serviceReference_increaseUsage(reference, &count);
+            if (count == 1) {
+                serviceRegistration_getService(registration, bundle, &service);
+                serviceReference_setService(reference, service);
+            }
+
+            /* NOTE the out argument of sr_getService should be 'const void**'
+               To ensure backwards compatability a cast is made instead.
+            */
+            serviceReference_getService(reference, (void **)out);
+        } else {
+            *out = NULL; //invalid service registration
+        }
+    } else {
+        serviceRegistry_logIllegalReference(registry, reference, refStatus);
+        status = CELIX_BUNDLE_EXCEPTION;
+    }
+    celixThreadRwlock_unlock(&registry->lock);
+
+	return status;
+}
+
+celix_status_t serviceRegistry_ungetService(service_registry_pt registry, bundle_pt bundle, service_reference_pt reference, bool *result) {
+	celix_status_t status = CELIX_SUCCESS;
+    service_registration_pt reg = NULL;
+    const void *service = NULL;
+    size_t count = 0;
+    celix_status_t subStatus = CELIX_SUCCESS;
+    reference_status_t refStatus;
+
+    celixThreadRwlock_readLock(&registry->lock);
+    serviceRegistry_checkReference(registry, reference, &refStatus);
+    celixThreadRwlock_unlock(&registry->lock);
+
+    if (refStatus == REF_ACTIVE) {
+        subStatus = serviceReference_decreaseUsage(reference, &count);
+        if (count == 0) {
+            /*NOTE the argument service of sr_getService should be 'const void**'
+              TO ensure backwards compatability a cast is made instead.
+              */
+            serviceReference_getService(reference, (void**)&service);
+            serviceReference_getServiceRegistration(reference, &reg);
+            if (reg != NULL) {
+                serviceRegistration_ungetService(reg, bundle, &service);
+            }
+        }
+    } else {
+        serviceRegistry_logIllegalReference(registry, reference, refStatus);
+        status = CELIX_BUNDLE_EXCEPTION;
+    }
+
+    if (result) {
+        *result = (subStatus == CELIX_SUCCESS);
+    }
+
+
+	return status;
+}
+
+static celix_status_t serviceRegistry_addHooks(service_registry_pt registry, const char* serviceName, const void* serviceObject __attribute__((unused)), service_registration_pt registration) {
+	celix_status_t status = CELIX_SUCCESS;
+
+	if (strcmp(OSGI_FRAMEWORK_LISTENER_HOOK_SERVICE_NAME, serviceName) == 0) {
+        celixThreadRwlock_writeLock(&registry->lock);
+		arrayList_add(registry->listenerHooks, registration);
+        celixThreadRwlock_unlock(&registry->lock);
+	}
+
+	return status;
+}
+
+static celix_status_t serviceRegistry_removeHook(service_registry_pt registry, service_registration_pt registration) {
+	celix_status_t status = CELIX_SUCCESS;
+	const char* serviceName = NULL;
+
+	properties_pt props = NULL;
+	serviceRegistration_getProperties(registration, &props);
+	serviceName = properties_get(props, (char *) OSGI_FRAMEWORK_OBJECTCLASS);
+	if (strcmp(OSGI_FRAMEWORK_LISTENER_HOOK_SERVICE_NAME, serviceName) == 0) {
+        celixThreadRwlock_writeLock(&registry->lock);
+		arrayList_removeElement(registry->listenerHooks, registration);
+        celixThreadRwlock_unlock(&registry->lock);
+	}
+
+	return status;
+}
+
+celix_status_t serviceRegistry_getListenerHooks(service_registry_pt registry, bundle_pt owner, array_list_pt *out) {
+	celix_status_t status;
+    array_list_pt result;
+
+    status = arrayList_create(&result);
+    if (status == CELIX_SUCCESS) {
+        unsigned int i;
+        unsigned size = arrayList_size(registry->listenerHooks);
+
+        for (i = 0; i < size; i += 1) {
+            celixThreadRwlock_readLock(&registry->lock);
+            service_registration_pt registration = arrayList_get(registry->listenerHooks, i);
+            serviceRegistration_retain(registration);
+            celixThreadRwlock_unlock(&registry->lock);
+
+            service_reference_pt reference = NULL;
+            serviceRegistry_getServiceReference(registry, owner, registration, &reference);
+            arrayList_add(result, reference);
+            serviceRegistration_release(registration);
+        }
+    }
+
+    if (status == CELIX_SUCCESS) {
+        *out = result;
+    } else {
+        if (result != NULL) {
+            arrayList_destroy(result);
+        }
+        framework_logIfError(logger, status, NULL, "Cannot get listener hooks");
+    }
+
+	return status;
+}
+
+celix_status_t serviceRegistry_servicePropertiesModified(service_registry_pt registry, service_registration_pt registration, properties_pt oldprops) {
+	if (registry->serviceChanged != NULL) {
+		registry->serviceChanged(registry->framework, OSGI_FRAMEWORK_SERVICE_EVENT_MODIFIED, registration, oldprops);
+	}
+	return CELIX_SUCCESS;
+}
+
+static celix_status_t serviceRegistry_getUsingBundles(service_registry_pt registry, service_registration_pt registration, array_list_pt *out) {
+    celix_status_t status;
+    array_list_pt bundles = NULL;
+    hash_map_iterator_pt iter;
+
+    status = arrayList_create(&bundles);
+    if (status == CELIX_SUCCESS) {
+        celixThreadRwlock_readLock(&registry->lock);
+        iter = hashMapIterator_create(registry->serviceReferences);
+        while (hashMapIterator_hasNext(iter)) {
+            hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
+            bundle_pt registrationUser = hashMapEntry_getKey(entry);
+            hash_map_pt regMap = hashMapEntry_getValue(entry);
+            if (hashMap_containsKey(regMap, (void*)registration->serviceId)) {
+                arrayList_add(bundles, registrationUser);
+            }
+        }
+        hashMapIterator_destroy(iter);
+        celixThreadRwlock_unlock(&registry->lock);
+    }
+
+    if (status == CELIX_SUCCESS) {
+        *out = bundles;
+    } else {
+        if (bundles != NULL) {
+            arrayList_destroy(bundles);
+        }
+    }
+
+    return status;
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/framework/src/service_registry_private.h
----------------------------------------------------------------------
diff --git a/framework/src/service_registry_private.h b/framework/src/service_registry_private.h
new file mode 100644
index 0000000..d68fe11
--- /dev/null
+++ b/framework/src/service_registry_private.h
@@ -0,0 +1,67 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+/*
+ * service_registry_private.h
+ *
+ *  \date       Feb 7, 2013
+ *  \author     <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright  Apache License, Version 2.0
+ */
+
+
+#ifndef SERVICE_REGISTRY_PRIVATE_H_
+#define SERVICE_REGISTRY_PRIVATE_H_
+
+#include "registry_callback_private.h"
+#include "service_registry.h"
+
+struct serviceRegistry {
+	framework_pt framework;
+	registry_callback_t callback;
+
+	hash_map_pt serviceRegistrations; //key = bundle (reg owner), value = list ( registration )
+	hash_map_pt serviceReferences; //key = bundle, value = map (key = serviceId, value = reference)
+
+	bool checkDeletedReferences; //If enabled. check if provided service references are still valid
+	hash_map_pt deletedServiceReferences; //key = ref pointer, value = bool
+
+	serviceChanged_function_pt serviceChanged;
+	unsigned long currentServiceId;
+
+	array_list_pt listenerHooks;
+
+	celix_thread_rwlock_t lock;
+};
+
+typedef enum reference_status_enum {
+	REF_ACTIVE,
+	REF_DELETED,
+	REF_UNKNOWN
+} reference_status_t;
+
+struct usageCount {
+	unsigned int count;
+	service_reference_pt reference;
+	void * service;
+	service_registration_pt registration;
+};
+
+typedef struct usageCount * usage_count_pt;
+
+#endif /* SERVICE_REGISTRY_PRIVATE_H_ */


Mime
View raw message