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, ®1); + serviceReference_getServiceRegistration(compareTo, ®2); + *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, ®istration); + 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, ®istration); + 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(®->lock, NULL); + + celixThreadRwlock_writeLock(®->lock); + serviceRegistration_initializeProperties(reg, dictionary); + celixThreadRwlock_unlock(®->lock); + + } else { + status = CELIX_ENOMEM; + } + + if (status == CELIX_SUCCESS) { + *out = reg; + } + + return status; +} + +void serviceRegistration_retain(service_registration_pt registration) { + celixThreadRwlock_writeLock(®istration->lock); + registration->refCount += 1; + celixThreadRwlock_unlock(®istration->lock); +} + +void serviceRegistration_release(service_registration_pt registration) { + celixThreadRwlock_writeLock(®istration->lock); + assert(registration->refCount > 0); + registration->refCount -= 1; + if (registration->refCount == 0) { + serviceRegistration_destroy(registration); + } else { + celixThreadRwlock_unlock(®istration->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(®istration->lock); + celixThreadRwlock_destroy(®istration->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(®istration->lock); + registration->svcObj = NULL; + celixThreadRwlock_unlock(®istration->lock); +} + +bool serviceRegistration_isValid(service_registration_pt registration) { + bool isValid; + if (registration != NULL) { + celixThreadRwlock_readLock(®istration->lock); + isValid = registration->svcObj != NULL; + celixThreadRwlock_unlock(®istration->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(®istration->lock); + notValidOrUnregistering = !serviceRegistration_isValid(registration) || registration->isUnregistering; + celixThreadRwlock_unlock(®istration->lock); + + registry_callback_t callback; + callback.unregister = NULL; + bundle_pt bundle = NULL; + + if (notValidOrUnregistering) { + status = CELIX_ILLEGAL_STATE; + } else { + celixThreadRwlock_writeLock(®istration->lock); + registration->isUnregistering = true; + bundle = registration->bundle; + callback = registration->callback; + celixThreadRwlock_unlock(®istration->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(®istration->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(®istration->lock); + return status; +} + +celix_status_t serviceRegistration_ungetService(service_registration_pt registration, bundle_pt bundle, const void** service) { + celixThreadRwlock_readLock(®istration->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(®istration->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(®istration->lock); + *properties = registration->properties; + celixThreadRwlock_unlock(®istration->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(®istration->lock); + oldProperties = registration->properties; + status = serviceRegistration_initializeProperties(registration, properties); + callback = registration->callback; + celixThreadRwlock_unlock(®istration->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(®istration->lock); + *bundle = registration->bundle; + celixThreadRwlock_unlock(®istration->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(®istration->lock); + *serviceName = registration->className; + celixThreadRwlock_unlock(®istration->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(®->listenerHooks); + + status = celixThreadRwlock_create(®->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(®istry->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(®istry->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(®istry->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(®istry->lock); + regs = (array_list_pt) hashMap_get(registry->serviceRegistrations, bundle); + if (regs == NULL) { + regs = NULL; + arrayList_create(®s); + hashMap_put(registry->serviceRegistrations, bundle, regs); + } + arrayList_add(regs, *registration); + celixThreadRwlock_unlock(®istry->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(®istry->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(®istry->lock); + + if (registry->serviceChanged != NULL) { + registry->serviceChanged(registry->framework, OSGI_FRAMEWORK_SERVICE_EVENT_UNREGISTERING, registration, NULL); + } + + + celixThreadRwlock_readLock(®istry->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(®istry->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(®istry->lock); + registrations = hashMap_get(registry->serviceRegistrations, bundle); + registrationsLeft = (registrations != NULL); + if (registrationsLeft) { + registrationsLeft = (arrayList_size(registrations) > 0); + } + celixThreadRwlock_unlock(®istry->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(®istry->lock); + registrations = hashMap_get(registry->serviceRegistrations, bundle); + registrationsLeft = (registrations != NULL); + if (registrationsLeft) { + registrationsLeft = (arrayList_size(registrations) > 0); + } + celixThreadRwlock_unlock(®istry->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(®istry->lock) == CELIX_SUCCESS) { + status = serviceRegistry_getServiceReference_internal(registry, owner, registration, out); + celixThreadRwlock_unlock(®istry->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(®istry->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(®istry->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(®istry->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(®istry->lock); + + return status; +} + + +celix_status_t serviceRegistry_ungetServiceReference(service_registry_pt registry, bundle_pt bundle, service_reference_pt reference) { + celix_status_t status = CELIX_SUCCESS; + bool destroyed = false; + size_t count = 0; + reference_status_t refStatus; + + celixThreadRwlock_writeLock(®istry->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(®istry->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, ®); + 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(®istry->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(®istry->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(®istry->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(®istry->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(®istry->lock); + serviceRegistry_checkReference(registry, reference, &refStatus); + if (refStatus == REF_ACTIVE) { + serviceReference_getServiceRegistration(reference, ®istration); + + 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(®istry->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(®istry->lock); + serviceRegistry_checkReference(registry, reference, &refStatus); + celixThreadRwlock_unlock(®istry->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, ®); + 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(®istry->lock); + arrayList_add(registry->listenerHooks, registration); + celixThreadRwlock_unlock(®istry->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(®istry->lock); + arrayList_removeElement(registry->listenerHooks, registration); + celixThreadRwlock_unlock(®istry->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(®istry->lock); + service_registration_pt registration = arrayList_get(registry->listenerHooks, i); + serviceRegistration_retain(registration); + celixThreadRwlock_unlock(®istry->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(®istry->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(®istry->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_ */
