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:[email protected]";>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:[email protected]";>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:[email protected]";>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:[email protected]";>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:[email protected]";>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:[email protected]";>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:[email protected]";>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:[email protected]";>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_ */

Reply via email to