You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celix.apache.org by pn...@apache.org on 2017/11/20 20:33:11 UTC
[14/46] celix git commit: CELIX-417: Initial refactoring for CMake
usage
http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/framework/src/resolver.c
----------------------------------------------------------------------
diff --git a/framework/src/resolver.c b/framework/src/resolver.c
new file mode 100644
index 0000000..256eff5
--- /dev/null
+++ b/framework/src/resolver.c
@@ -0,0 +1,495 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements. See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership. The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+/*
+ * resolver.c
+ *
+ * \date Jul 13, 2010
+ * \author <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ * \copyright Apache License, Version 2.0
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "resolver.h"
+#include "linked_list_iterator.h"
+#include "bundle.h"
+#include "celix_log.h"
+
+struct capabilityList {
+ char * serviceName;
+ linked_list_pt capabilities;
+};
+
+typedef struct capabilityList * capability_list_pt;
+
+struct candidateSet {
+ module_pt module;
+ requirement_pt requirement;
+ linked_list_pt candidates;
+};
+
+typedef struct candidateSet * candidate_set_pt;
+
+// List containing module_ts
+linked_list_pt m_modules = NULL;
+// List containing capability_t_LISTs
+linked_list_pt m_unresolvedServices = NULL;
+// List containing capability_t_LISTs
+linked_list_pt m_resolvedServices = NULL;
+
+int resolver_populateCandidatesMap(hash_map_pt candidatesMap, module_pt targetModule);
+capability_list_pt resolver_getCapabilityList(linked_list_pt list, const char* name);
+void resolver_removeInvalidCandidate(module_pt module, hash_map_pt candidates, linked_list_pt invalid);
+linked_list_pt resolver_populateWireMap(hash_map_pt candidates, module_pt importer, linked_list_pt wireMap);
+
+linked_list_pt resolver_resolve(module_pt root) {
+ hash_map_pt candidatesMap = NULL;
+ linked_list_pt wireMap = NULL;
+ linked_list_pt resolved = NULL;
+ hash_map_iterator_pt iter = NULL;
+
+ if (module_isResolved(root)) {
+ return NULL;
+ }
+
+ candidatesMap = hashMap_create(NULL, NULL, NULL, NULL);
+
+ if (resolver_populateCandidatesMap(candidatesMap, root) != 0) {
+ hash_map_iterator_pt iter = hashMapIterator_create(candidatesMap);
+ while (hashMapIterator_hasNext(iter)) {
+ hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
+ linked_list_pt value = hashMapEntry_getValue(entry);
+ hashMapIterator_remove(iter);
+ if (value != NULL) {
+ linked_list_iterator_pt candSetIter = linkedListIterator_create(value, 0);
+ while (linkedListIterator_hasNext(candSetIter)) {
+ candidate_set_pt set = linkedListIterator_next(candSetIter);
+ linkedList_destroy(set->candidates);
+ free(set);
+ linkedListIterator_remove(candSetIter);
+ }
+ linkedListIterator_destroy(candSetIter);
+ linkedList_destroy(value);
+ }
+ }
+ hashMapIterator_destroy(iter);
+ hashMap_destroy(candidatesMap, false, false);
+ return NULL;
+ }
+
+ linkedList_create(&wireMap);
+ resolved = resolver_populateWireMap(candidatesMap, root, wireMap);
+ iter = hashMapIterator_create(candidatesMap);
+ while (hashMapIterator_hasNext(iter)) {
+ hash_map_entry_pt entry = hashMapIterator_nextEntry(iter);
+ linked_list_pt value = hashMapEntry_getValue(entry);
+ hashMapIterator_remove(iter);
+ if (value != NULL) {
+ linked_list_iterator_pt candSetIter = linkedListIterator_create(value, 0);
+ while (linkedListIterator_hasNext(candSetIter)) {
+ candidate_set_pt set = linkedListIterator_next(candSetIter);
+ linkedList_destroy(set->candidates);
+ free(set);
+ linkedListIterator_remove(candSetIter);
+ }
+ linkedListIterator_destroy(candSetIter);
+ linkedList_destroy(value);
+ }
+ }
+ hashMapIterator_destroy(iter);
+ hashMap_destroy(candidatesMap, false, false);
+ return resolved;
+}
+
+int resolver_populateCandidatesMap(hash_map_pt candidatesMap, module_pt targetModule) {
+ linked_list_pt candSetList;
+ linked_list_pt candidates;
+ linked_list_pt invalid;
+
+ if (hashMap_containsKey(candidatesMap, targetModule)) {
+ return 0;
+ }
+
+ hashMap_put(candidatesMap, targetModule, NULL);
+
+ if (linkedList_create(&candSetList) == CELIX_SUCCESS) {
+ int i;
+ for (i = 0; i < linkedList_size(module_getRequirements(targetModule)); i++) {
+ capability_list_pt capList;
+ requirement_pt req;
+ const char *targetName = NULL;
+ req = (requirement_pt) linkedList_get(module_getRequirements(targetModule), i);
+ requirement_getTargetName(req, &targetName);
+ capList = resolver_getCapabilityList(m_resolvedServices, targetName);
+
+ if (linkedList_create(&candidates) == CELIX_SUCCESS) {
+ int c;
+ for (c = 0; (capList != NULL) && (c < linkedList_size(capList->capabilities)); c++) {
+ capability_pt cap = (capability_pt) linkedList_get(capList->capabilities, c);
+ bool satisfied = false;
+ requirement_isSatisfied(req, cap, &satisfied);
+ if (satisfied) {
+ linkedList_addElement(candidates, cap);
+ }
+ }
+ capList = resolver_getCapabilityList(m_unresolvedServices, targetName);
+ for (c = 0; (capList != NULL) && (c < linkedList_size(capList->capabilities)); c++) {
+ capability_pt cap = (capability_pt) linkedList_get(capList->capabilities, c);
+ bool satisfied = false;
+ requirement_isSatisfied(req, cap, &satisfied);
+ if (satisfied) {
+ linkedList_addElement(candidates, cap);
+ }
+ }
+
+ if (linkedList_size(candidates) > 0) {
+ linked_list_iterator_pt iterator = NULL;
+ for (iterator = linkedListIterator_create(candidates, 0); linkedListIterator_hasNext(iterator);) {
+ capability_pt candidate = (capability_pt) linkedListIterator_next(iterator);
+ module_pt module = NULL;
+ capability_getModule(candidate, &module);
+ if (!module_isResolved(module)) {
+ if (resolver_populateCandidatesMap(candidatesMap, module) != 0) {
+ linkedListIterator_remove(iterator);
+ }
+ }
+ }
+ linkedListIterator_destroy(iterator);
+ }
+
+ if (linkedList_size(candidates) == 0) {
+ if (linkedList_create(&invalid) == CELIX_SUCCESS) {
+ const char *name = NULL;
+ resolver_removeInvalidCandidate(targetModule, candidatesMap, invalid);
+
+ module_getSymbolicName(targetModule, &name);
+
+ linkedList_destroy(invalid);
+ fw_log(logger, OSGI_FRAMEWORK_LOG_INFO, "Unable to resolve: %s, %s\n", name, targetName);
+ }
+ linkedList_destroy(candidates);
+ linkedList_destroy(candSetList);
+ return -1;
+ } else if (linkedList_size(candidates) > 0) {
+ candidate_set_pt cs = (candidate_set_pt) malloc(sizeof(*cs));
+ cs->candidates = candidates;
+ cs->module = targetModule;
+ cs->requirement = req;
+ linkedList_addElement(candSetList, cs);
+ }
+
+ }
+ }
+ hashMap_put(candidatesMap, targetModule, candSetList);
+ }
+ return 0;
+}
+
+void resolver_removeInvalidCandidate(module_pt invalidModule, hash_map_pt candidates, linked_list_pt invalid) {
+ hash_map_iterator_pt iterator;
+ hashMap_remove(candidates, invalidModule);
+
+ for (iterator = hashMapIterator_create(candidates); hashMapIterator_hasNext(iterator);) {
+ hash_map_entry_pt entry = hashMapIterator_nextEntry(iterator);
+ linked_list_pt candSetList = (linked_list_pt) hashMapEntry_getValue(entry);
+ if (candSetList != NULL) {
+ linked_list_iterator_pt itCandSetList;
+ for (itCandSetList = linkedListIterator_create(candSetList, 0); linkedListIterator_hasNext(itCandSetList);) {
+ candidate_set_pt set = (candidate_set_pt) linkedListIterator_next(itCandSetList);
+ linked_list_iterator_pt candIter;
+ for (candIter = linkedListIterator_create(set->candidates, 0); linkedListIterator_hasNext(candIter);) {
+ capability_pt candCap = (capability_pt) linkedListIterator_next(candIter);
+ module_pt module = NULL;
+ capability_getModule(candCap, &module);
+ if (module == invalidModule) {
+ linkedListIterator_remove(candIter);
+ if (linkedList_size(set->candidates) == 0) {
+ linkedListIterator_remove(itCandSetList);
+ if (module != invalidModule && linkedList_contains(invalid, module)) {
+ linkedList_addElement(invalid, module);
+ }
+ }
+ break;
+ }
+ }
+ linkedListIterator_destroy(candIter);
+ }
+ linkedListIterator_destroy(itCandSetList);
+ }
+ }
+ hashMapIterator_destroy(iterator);
+
+ if (linkedList_size(invalid) > 0) {
+ while (!linkedList_isEmpty(invalid)) {
+ module_pt m = (module_pt) linkedList_removeIndex(invalid, 0);
+ resolver_removeInvalidCandidate(m, candidates, invalid);
+ }
+ }
+}
+
+void resolver_addModule(module_pt module) {
+
+ if (m_modules == NULL) {
+ linkedList_create(&m_modules);
+ linkedList_create(&m_unresolvedServices);
+ linkedList_create(&m_resolvedServices);
+ }
+
+ if (m_modules != NULL && m_unresolvedServices != NULL) {
+ int i;
+
+ linkedList_addElement(m_modules, module);
+
+ for (i = 0; i < linkedList_size(module_getCapabilities(module)); i++) {
+ const char *serviceName = NULL;
+ capability_list_pt list = NULL;
+ capability_pt cap;
+
+ cap = (capability_pt) linkedList_get(module_getCapabilities(module), i);
+ capability_getServiceName(cap, &serviceName);
+ list = resolver_getCapabilityList(m_unresolvedServices, serviceName);
+ if (list == NULL) {
+ list = (capability_list_pt) malloc(sizeof(*list));
+ if (list != NULL) {
+ list->serviceName = strdup(serviceName);
+ if (linkedList_create(&list->capabilities) == CELIX_SUCCESS) {
+ linkedList_addElement(m_unresolvedServices, list);
+ }
+ else{
+ free(list->serviceName);
+ free(list);
+ list=NULL;
+ }
+ }
+ }
+ if(list != NULL){
+ linkedList_addElement(list->capabilities, cap);
+ }
+ }
+ }
+}
+
+void resolver_removeModule(module_pt module) {
+ linked_list_pt caps = NULL;
+ linkedList_removeElement(m_modules, module);
+ caps = module_getCapabilities(module);
+ if (caps != NULL) {
+ int i = 0;
+ for (i = 0; i < linkedList_size(caps); i++) {
+ capability_pt cap = (capability_pt) linkedList_get(caps, i);
+ const char *serviceName = NULL;
+ capability_list_pt list;
+ capability_getServiceName(cap, &serviceName);
+ list = resolver_getCapabilityList(m_unresolvedServices, serviceName);
+ if (list != NULL) {
+ linkedList_removeElement(list->capabilities, cap);
+
+ if (linkedList_isEmpty(list->capabilities)) {
+ linkedList_removeElement(m_unresolvedServices, list);
+ linkedList_destroy(list->capabilities);
+ free(list->serviceName);
+ free(list);
+ }
+ }
+ list = resolver_getCapabilityList(m_resolvedServices, serviceName);
+ if (list != NULL) {
+ linkedList_removeElement(list->capabilities, cap);
+
+ if (linkedList_isEmpty(list->capabilities)) {
+ linkedList_removeElement(m_resolvedServices, list);
+ linkedList_destroy(list->capabilities);
+ free(list->serviceName);
+ free(list);
+ }
+ }
+ }
+ }
+ if (linkedList_isEmpty(m_modules)) {
+ linkedList_destroy(m_modules);
+ m_modules = NULL;
+
+ if (!linkedList_isEmpty(m_unresolvedServices)) {
+ // #TODO: Something is wrong, not all modules have been removed from the resolver
+ fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Unexpected entries in unresolved module list");
+ }
+ linkedList_destroy(m_unresolvedServices);
+ m_unresolvedServices = NULL;
+ if (!linkedList_isEmpty(m_resolvedServices)) {
+ // #TODO: Something is wrong, not all modules have been removed from the resolver
+ fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Unexpected entries in resolved module list");
+ }
+ linkedList_destroy(m_resolvedServices);
+ m_resolvedServices = NULL;
+ }
+}
+
+void resolver_moduleResolved(module_pt module) {
+
+ if (module_isResolved(module)) {
+ linked_list_pt capsCopy = NULL;
+
+ if (linkedList_create(&capsCopy) == CELIX_SUCCESS) {
+ linked_list_pt wires = NULL;
+ int capIdx;
+
+ for (capIdx = 0; (module_getCapabilities(module) != NULL) && (capIdx < linkedList_size(module_getCapabilities(module))); capIdx++) {
+ capability_pt cap = (capability_pt) linkedList_get(module_getCapabilities(module), capIdx);
+ const char *serviceName = NULL;
+ capability_list_pt list;
+ capability_getServiceName(cap, &serviceName);
+ list = resolver_getCapabilityList(m_unresolvedServices, serviceName);
+ if(list != NULL){
+ linkedList_removeElement(list->capabilities, cap);
+ }
+
+ linkedList_addElement(capsCopy, cap);
+ }
+
+ wires = module_getWires(module);
+ for (capIdx = 0; (capsCopy != NULL) && (capIdx < linkedList_size(capsCopy)); capIdx++) {
+ capability_pt cap = linkedList_get(capsCopy, capIdx);
+
+ int wireIdx = 0;
+ for (wireIdx = 0; (wires != NULL) && (wireIdx < linkedList_size(wires)); wireIdx++) {
+ wire_pt wire = (wire_pt) linkedList_get(wires, wireIdx);
+ requirement_pt req = NULL;
+ bool satisfied = false;
+ wire_getRequirement(wire, &req);
+ requirement_isSatisfied(req, cap, &satisfied);
+ if (satisfied) {
+ linkedList_set(capsCopy, capIdx, NULL);
+ break;
+ }
+ }
+ }
+
+ for (capIdx = 0; (capsCopy != NULL) && (capIdx < linkedList_size(capsCopy)); capIdx++) {
+ capability_pt cap = linkedList_get(capsCopy, capIdx);
+
+ if (cap != NULL) {
+ const char *serviceName = NULL;
+ capability_list_pt list = NULL;
+ capability_getServiceName(cap, &serviceName);
+
+ list = resolver_getCapabilityList(m_resolvedServices, serviceName);
+ if (list == NULL) {
+ list = (capability_list_pt) malloc(sizeof(*list));
+ if (list != NULL) {
+ list->serviceName = strdup(serviceName);
+ if (linkedList_create(&list->capabilities) == CELIX_SUCCESS) {
+ linkedList_addElement(m_resolvedServices, list);
+ }
+ else{
+ free(list->serviceName);
+ free(list);
+ list=NULL;
+ }
+ }
+ }
+ if(list != NULL){
+ linkedList_addElement(list->capabilities, cap);
+ }
+ }
+ }
+
+ linkedList_destroy(capsCopy);
+ }
+ }
+}
+
+capability_list_pt resolver_getCapabilityList(linked_list_pt list, const char * name) {
+ capability_list_pt capabilityList = NULL;
+ linked_list_iterator_pt iterator = linkedListIterator_create(list, 0);
+ while (linkedListIterator_hasNext(iterator)) {
+ capability_list_pt services = (capability_list_pt) linkedListIterator_next(iterator);
+ if (strcmp(services->serviceName, name) == 0) {
+ capabilityList = services;
+ break;
+ }
+ }
+ linkedListIterator_destroy(iterator);
+ return capabilityList;
+}
+
+linked_list_pt resolver_populateWireMap(hash_map_pt candidates, module_pt importer, linked_list_pt wireMap) {
+ linked_list_pt serviceWires;
+
+ if (candidates && importer && wireMap) {
+ linked_list_pt candSetList = NULL;
+ bool resolved = false;
+
+ if (module_isResolved(importer)) {
+ // already resolved
+ resolved = true;
+ }
+ if (!resolved) {
+ bool self = false;
+ linked_list_iterator_pt wit = linkedListIterator_create(wireMap, 0);
+ while (linkedListIterator_hasNext(wit)) {
+ importer_wires_pt iw = linkedListIterator_next(wit);
+ if (iw->importer == importer) {
+ // Do not resolve yourself
+ self = true;
+ break;
+ }
+ }
+ linkedListIterator_destroy(wit);
+
+ if (!self) {
+ candSetList = (linked_list_pt) hashMap_get(candidates, importer);
+
+ if (linkedList_create(&serviceWires) == CELIX_SUCCESS) {
+// if (linkedList_create(&emptyWires) == CELIX_SUCCESS) {
+ int candSetIdx = 0;
+
+ // hashMap_put(wireMap, importer, emptyWires);
+
+ const char *mname = NULL;
+ module_getSymbolicName(importer, &mname);
+
+ importer_wires_pt importerWires = malloc(sizeof(*importerWires));
+ importerWires->importer = importer;
+ importerWires->wires = NULL;
+ linkedList_addElement(wireMap, importerWires);
+
+ for (candSetIdx = 0; candSetIdx < linkedList_size(candSetList); candSetIdx++) {
+ candidate_set_pt cs = (candidate_set_pt) linkedList_get(candSetList, candSetIdx);
+
+ module_pt module = NULL;
+ capability_getModule(((capability_pt) linkedList_get(cs->candidates, 0)), &module);
+ if (importer != module) {
+ wire_pt wire = NULL;
+ wire_create(importer, cs->requirement, module, ((capability_pt) linkedList_get(cs->candidates, 0)), &wire);
+ linkedList_addElement(serviceWires, wire);
+ }
+
+ wireMap = resolver_populateWireMap(candidates, module, wireMap);
+ }
+
+ importerWires->wires = serviceWires;
+ // hashMap_put(wireMap, importer, serviceWires);
+// }
+ }
+ }
+ }
+ }
+
+ return wireMap;
+}
http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/framework/src/resolver.h
----------------------------------------------------------------------
diff --git a/framework/src/resolver.h b/framework/src/resolver.h
new file mode 100644
index 0000000..87440e9
--- /dev/null
+++ b/framework/src/resolver.h
@@ -0,0 +1,45 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements. See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership. The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+/*
+ * resolver.h
+ *
+ * \date Jul 13, 2010
+ * \author <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ * \copyright Apache License, Version 2.0
+ */
+
+#ifndef RESOLVER_H_
+#define RESOLVER_H_
+
+#include "module.h"
+#include "wire.h"
+#include "hash_map.h"
+
+struct importer_wires {
+ module_pt importer;
+ linked_list_pt wires;
+};
+typedef struct importer_wires *importer_wires_pt;
+
+linked_list_pt resolver_resolve(module_pt root);
+void resolver_moduleResolved(module_pt module);
+void resolver_addModule(module_pt module);
+void resolver_removeModule(module_pt module);
+
+#endif /* RESOLVER_H_ */
http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/framework/src/service_reference.c
----------------------------------------------------------------------
diff --git a/framework/src/service_reference.c b/framework/src/service_reference.c
new file mode 100644
index 0000000..545426d
--- /dev/null
+++ b/framework/src/service_reference.c
@@ -0,0 +1,378 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements. See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership. The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+/*
+ * service_reference.c
+ *
+ * \date Jul 20, 2010
+ * \author <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ * \copyright Apache License, Version 2.0
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <constants.h>
+#include <stdint.h>
+#include <utils.h>
+#include <assert.h>
+
+#include "service_reference.h"
+
+#include "service_reference_private.h"
+#include "service_registration_private.h"
+
+static void serviceReference_destroy(service_reference_pt);
+static void serviceReference_logWarningUsageCountBelowZero(service_reference_pt ref);
+
+celix_status_t serviceReference_create(registry_callback_t callback, bundle_pt referenceOwner, service_registration_pt registration, service_reference_pt *out) {
+ celix_status_t status = CELIX_SUCCESS;
+
+ service_reference_pt ref = calloc(1, sizeof(*ref));
+ if (!ref) {
+ status = CELIX_ENOMEM;
+ } else {
+ ref->callback = callback;
+ ref->referenceOwner = referenceOwner;
+ ref->registration = registration;
+ ref->service = NULL;
+ serviceRegistration_getBundle(registration, &ref->registrationBundle);
+ celixThreadRwlock_create(&ref->lock, NULL);
+ ref->refCount = 1;
+ ref->usageCount = 0;
+
+ serviceRegistration_retain(ref->registration);
+ }
+
+ if (status == CELIX_SUCCESS) {
+ *out = ref;
+ }
+
+ framework_logIfError(logger, status, NULL, "Cannot create service reference");
+
+ return status;
+}
+
+celix_status_t serviceReference_retain(service_reference_pt ref) {
+ celixThreadRwlock_writeLock(&ref->lock);
+ ref->refCount += 1;
+ celixThreadRwlock_unlock(&ref->lock);
+ return CELIX_SUCCESS;
+}
+
+celix_status_t serviceReference_release(service_reference_pt ref, bool *out) {
+ bool destroyed = false;
+ celixThreadRwlock_writeLock(&ref->lock);
+ assert(ref->refCount > 0);
+ ref->refCount -= 1;
+ if (ref->refCount == 0) {
+ if (ref->registration != NULL) {
+ serviceRegistration_release(ref->registration);
+ }
+ celixThreadRwlock_unlock(&ref->lock);
+ serviceReference_destroy(ref);
+ destroyed = true;
+ } else {
+ celixThreadRwlock_unlock(&ref->lock);
+ }
+
+ if (out) {
+ *out = destroyed;
+ }
+ return CELIX_SUCCESS;
+}
+
+celix_status_t serviceReference_increaseUsage(service_reference_pt ref, size_t *out) {
+ //fw_log(logger, OSGI_FRAMEWORK_LOG_DEBUG, "Destroying service reference %p\n", ref);
+ size_t local = 0;
+ celixThreadRwlock_writeLock(&ref->lock);
+ ref->usageCount += 1;
+ local = ref->usageCount;
+ celixThreadRwlock_unlock(&ref->lock);
+ if (out) {
+ *out = local;
+ }
+ return CELIX_SUCCESS;
+}
+
+celix_status_t serviceReference_decreaseUsage(service_reference_pt ref, size_t *out) {
+ celix_status_t status = CELIX_SUCCESS;
+ size_t localCount = 0;
+ celixThreadRwlock_writeLock(&ref->lock);
+ if (ref->usageCount == 0) {
+ serviceReference_logWarningUsageCountBelowZero(ref);
+ status = CELIX_BUNDLE_EXCEPTION;
+ } else {
+ ref->usageCount -= 1;
+ }
+ localCount = ref->usageCount;
+ celixThreadRwlock_unlock(&ref->lock);
+
+ if (out) {
+ *out = localCount;
+ }
+ return status;
+}
+
+static void serviceReference_logWarningUsageCountBelowZero(service_reference_pt ref __attribute__((unused))) {
+ fw_log(logger, OSGI_FRAMEWORK_LOG_WARNING, "Cannot decrease service usage count below 0\n");
+}
+
+
+celix_status_t serviceReference_getUsageCount(service_reference_pt ref, size_t *count) {
+ celix_status_t status = CELIX_SUCCESS;
+ celixThreadRwlock_readLock(&ref->lock);
+ *count = ref->usageCount;
+ celixThreadRwlock_unlock(&ref->lock);
+ return status;
+}
+
+celix_status_t serviceReference_getReferenceCount(service_reference_pt ref, size_t *count) {
+ celix_status_t status = CELIX_SUCCESS;
+ celixThreadRwlock_readLock(&ref->lock);
+ *count = ref->refCount;
+ celixThreadRwlock_unlock(&ref->lock);
+ return status;
+}
+
+celix_status_t serviceReference_getService(service_reference_pt ref, void **service) {
+ celix_status_t status = CELIX_SUCCESS;
+ celixThreadRwlock_readLock(&ref->lock);
+ /*NOTE the service argument should be 'const void**'
+ To ensure backwards compatability a cast is made instead.
+ */
+ *service = (const void**) ref->service;
+ celixThreadRwlock_unlock(&ref->lock);
+ return status;
+}
+
+celix_status_t serviceReference_setService(service_reference_pt ref, const void *service) {
+ celix_status_t status = CELIX_SUCCESS;
+ celixThreadRwlock_writeLock(&ref->lock);
+ ref->service = service;
+ celixThreadRwlock_unlock(&ref->lock);
+ return status;
+}
+
+static void serviceReference_destroy(service_reference_pt ref) {
+ assert(ref->refCount == 0);
+ celixThreadRwlock_destroy(&ref->lock);
+ ref->registration = NULL;
+ free(ref);
+}
+
+celix_status_t serviceReference_getBundle(service_reference_pt ref, bundle_pt *bundle) {
+ celix_status_t status = CELIX_SUCCESS;
+ celixThreadRwlock_readLock(&ref->lock);
+ if (ref->registration != NULL) {
+ *bundle = ref->registrationBundle;
+ }
+ celixThreadRwlock_unlock(&ref->lock);
+ return status;
+}
+
+celix_status_t serviceReference_getOwner(service_reference_pt ref, bundle_pt *owner) {
+ celix_status_t status = CELIX_SUCCESS;
+ celixThreadRwlock_readLock(&ref->lock);
+ *owner = ref->referenceOwner;
+ celixThreadRwlock_unlock(&ref->lock);
+ return status;
+}
+
+celix_status_t serviceReference_getServiceRegistration(service_reference_pt ref, service_registration_pt *out) {
+ if (ref != NULL) {
+ celixThreadRwlock_readLock(&ref->lock);
+ *out = ref->registration;
+ celixThreadRwlock_unlock(&ref->lock);
+ return CELIX_SUCCESS;
+ } else {
+ return CELIX_ILLEGAL_ARGUMENT;
+ }
+}
+
+celix_status_t serviceReference_getProperty(service_reference_pt ref, const char* key, const char** value) {
+ celix_status_t status = CELIX_SUCCESS;
+ properties_pt props = NULL;
+ celixThreadRwlock_readLock(&ref->lock);
+ if (ref->registration != NULL) {
+ status = serviceRegistration_getProperties(ref->registration, &props);
+ if (status == CELIX_SUCCESS) {
+ *value = (char*) properties_get(props, key);
+ }
+ } else {
+ *value = NULL;
+ }
+ celixThreadRwlock_unlock(&ref->lock);
+ return status;
+}
+
+FRAMEWORK_EXPORT celix_status_t serviceReference_getPropertyKeys(service_reference_pt ref, char **keys[], unsigned int *size) {
+ celix_status_t status = CELIX_SUCCESS;
+ properties_pt props = NULL;
+
+ celixThreadRwlock_readLock(&ref->lock);
+ serviceRegistration_getProperties(ref->registration, &props);
+ hash_map_iterator_pt it;
+ int i = 0;
+ int vsize = hashMap_size(props);
+ *size = (unsigned int)vsize;
+ *keys = malloc(vsize * sizeof(**keys));
+ it = hashMapIterator_create(props);
+ while (hashMapIterator_hasNext(it)) {
+ (*keys)[i] = hashMapIterator_nextKey(it);
+ i++;
+ }
+ hashMapIterator_destroy(it);
+ celixThreadRwlock_unlock(&ref->lock);
+ return status;
+}
+
+celix_status_t serviceReference_invalidate(service_reference_pt ref) {
+ assert(ref != NULL);
+ celix_status_t status = CELIX_SUCCESS;
+ service_registration_pt reg = NULL;
+ celixThreadRwlock_writeLock(&ref->lock);
+ reg = ref->registration;
+ ref->registration = NULL;
+ celixThreadRwlock_unlock(&ref->lock);
+
+ if (reg != NULL) {
+ serviceRegistration_release(reg);
+ }
+ return status;
+}
+
+celix_status_t serviceReference_isValid(service_reference_pt ref, bool *result) {
+ celixThreadRwlock_readLock(&ref->lock);
+ (*result) = ref->registration != NULL;
+ celixThreadRwlock_unlock(&ref->lock);
+ return CELIX_SUCCESS;
+}
+
+bool serviceReference_isAssignableTo(service_reference_pt reference __attribute__((unused)), bundle_pt requester __attribute__((unused)), const char* serviceName __attribute__((unused))) {
+ bool allow = true;
+
+ /*NOTE for now always true. It would be nice to be able to do somechecks if the services are really assignable.
+ */
+
+ return allow;
+}
+
+celix_status_t serviceReference_equals(service_reference_pt reference, service_reference_pt compareTo, bool *equal) {
+ celix_status_t status = CELIX_SUCCESS;
+ if (reference != NULL && compareTo != NULL) {
+ service_registration_pt reg1;
+ service_registration_pt reg2;
+ serviceReference_getServiceRegistration(reference, ®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:dev@celix.apache.org">Apache Celix Project Team</a>
+ * \copyright Apache License, Version 2.0
+ */
+
+
+#ifndef SERVICE_REFERENCE_PRIVATE_H_
+#define SERVICE_REFERENCE_PRIVATE_H_
+
+#include "registry_callback_private.h"
+#include "service_reference.h"
+
+
+struct serviceReference {
+ registry_callback_t callback;
+ bundle_pt referenceOwner;
+ struct serviceRegistration * registration;
+ bundle_pt registrationBundle;
+ const void* service;
+
+ size_t refCount;
+ size_t usageCount;
+
+ celix_thread_rwlock_t lock;
+};
+
+celix_status_t serviceReference_create(registry_callback_t callback, bundle_pt referenceOwner, service_registration_pt registration, service_reference_pt *reference);
+
+celix_status_t serviceReference_retain(service_reference_pt ref);
+celix_status_t serviceReference_release(service_reference_pt ref, bool *destroyed);
+
+celix_status_t serviceReference_increaseUsage(service_reference_pt ref, size_t *updatedCount);
+celix_status_t serviceReference_decreaseUsage(service_reference_pt ref, size_t *updatedCount);
+
+celix_status_t serviceReference_invalidate(service_reference_pt reference);
+celix_status_t serviceReference_isValid(service_reference_pt reference, bool *result);
+
+celix_status_t serviceReference_getUsageCount(service_reference_pt reference, size_t *count);
+celix_status_t serviceReference_getReferenceCount(service_reference_pt reference, size_t *count);
+
+celix_status_t serviceReference_setService(service_reference_pt ref, const void *service);
+celix_status_t serviceReference_getService(service_reference_pt reference, void **service);
+
+celix_status_t serviceReference_getOwner(service_reference_pt reference, bundle_pt *owner);
+
+
+
+#endif /* SERVICE_REFERENCE_PRIVATE_H_ */
http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/framework/src/service_registration.c
----------------------------------------------------------------------
diff --git a/framework/src/service_registration.c b/framework/src/service_registration.c
new file mode 100644
index 0000000..5d23dbf
--- /dev/null
+++ b/framework/src/service_registration.c
@@ -0,0 +1,291 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements. See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership. The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+/*
+ * service_registration.c
+ *
+ * \date Aug 6, 2010
+ * \author <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ * \copyright Apache License, Version 2.0
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "service_registration_private.h"
+#include "constants.h"
+
+static celix_status_t serviceRegistration_initializeProperties(service_registration_pt registration, properties_pt properties);
+static celix_status_t serviceRegistration_createInternal(registry_callback_t callback, bundle_pt bundle, const char* serviceName, unsigned long serviceId,
+ const void * serviceObject, properties_pt dictionary, bool isFactory, service_registration_pt *registration);
+static celix_status_t serviceRegistration_destroy(service_registration_pt registration);
+
+service_registration_pt serviceRegistration_create(registry_callback_t callback, bundle_pt bundle, const char* serviceName, unsigned long serviceId, const void * serviceObject, properties_pt dictionary) {
+ service_registration_pt registration = NULL;
+ serviceRegistration_createInternal(callback, bundle, serviceName, serviceId, serviceObject, dictionary, false, ®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:dev@celix.apache.org">Apache Celix Project Team</a>
+ * \copyright Apache License, Version 2.0
+ */
+
+
+#ifndef SERVICE_REGISTRATION_PRIVATE_H_
+#define SERVICE_REGISTRATION_PRIVATE_H_
+
+#include "registry_callback_private.h"
+#include "service_registration.h"
+
+struct serviceRegistration {
+ registry_callback_t callback;
+
+ char * className;
+ bundle_pt bundle;
+ properties_pt properties;
+ const void * svcObj;
+ unsigned long serviceId;
+
+ bool isUnregistering;
+
+ bool isServiceFactory;
+ const void *serviceFactory;
+
+ struct service *services;
+ int nrOfServices;
+
+ size_t refCount; //protected by mutex
+
+ celix_thread_rwlock_t lock;
+};
+
+service_registration_pt serviceRegistration_create(registry_callback_t callback, bundle_pt bundle, const char* serviceName, unsigned long serviceId, const void * serviceObject, properties_pt dictionary);
+service_registration_pt serviceRegistration_createServiceFactory(registry_callback_t callback, bundle_pt bundle, const char* serviceName, unsigned long serviceId, const void * serviceObject, properties_pt dictionary);
+
+void serviceRegistration_retain(service_registration_pt registration);
+void serviceRegistration_release(service_registration_pt registration);
+
+bool serviceRegistration_isValid(service_registration_pt registration);
+void serviceRegistration_invalidate(service_registration_pt registration);
+
+celix_status_t serviceRegistration_getService(service_registration_pt registration, bundle_pt bundle, const void **service);
+celix_status_t serviceRegistration_ungetService(service_registration_pt registration, bundle_pt bundle, const void **service);
+
+celix_status_t serviceRegistration_getBundle(service_registration_pt registration, bundle_pt *bundle);
+celix_status_t serviceRegistration_getServiceName(service_registration_pt registration, const char **serviceName);
+
+#endif /* SERVICE_REGISTRATION_PRIVATE_H_ */
http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/framework/src/service_registry.c
----------------------------------------------------------------------
diff --git a/framework/src/service_registry.c b/framework/src/service_registry.c
new file mode 100644
index 0000000..d27cc32
--- /dev/null
+++ b/framework/src/service_registry.c
@@ -0,0 +1,800 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements. See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership. The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+/*
+ * service_registry.c
+ *
+ * \date Aug 6, 2010
+ * \author <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ * \copyright Apache License, Version 2.0
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "service_registry_private.h"
+#include "service_registration_private.h"
+#include "listener_hook_service.h"
+#include "constants.h"
+#include "service_reference_private.h"
+#include "framework_private.h"
+
+#ifdef DEBUG
+#define CHECK_DELETED_REFERENCES true
+#else
+#define CHECK_DELETED_REFERENCES false
+#endif
+
+static celix_status_t serviceRegistry_registerServiceInternal(service_registry_pt registry, bundle_pt bundle, const char* serviceName, const void * serviceObject, properties_pt dictionary, bool isFactory, service_registration_pt *registration);
+static celix_status_t serviceRegistry_addHooks(service_registry_pt registry, const char* serviceName, const void *serviceObject, service_registration_pt registration);
+static celix_status_t serviceRegistry_removeHook(service_registry_pt registry, service_registration_pt registration);
+static void serviceRegistry_logWarningServiceReferenceUsageCount(service_registry_pt registry, bundle_pt bundle, service_reference_pt ref, size_t usageCount, size_t refCount);
+static void serviceRegistry_logWarningServiceRegistration(service_registry_pt registry, service_registration_pt reg);
+static celix_status_t serviceRegistry_checkReference(service_registry_pt registry, service_reference_pt ref,
+ reference_status_t *refStatus);
+static void serviceRegistry_logIllegalReference(service_registry_pt registry, service_reference_pt reference,
+ reference_status_t refStatus);
+static celix_status_t serviceRegistry_setReferenceStatus(service_registry_pt registry, service_reference_pt reference,
+ bool deleted);
+static celix_status_t serviceRegistry_getUsingBundles(service_registry_pt registry, service_registration_pt reg, array_list_pt *bundles);
+static celix_status_t serviceRegistry_getServiceReference_internal(service_registry_pt registry, bundle_pt owner, service_registration_pt registration, service_reference_pt *out);
+
+celix_status_t serviceRegistry_create(framework_pt framework, serviceChanged_function_pt serviceChanged, service_registry_pt *out) {
+ celix_status_t status;
+
+ service_registry_pt reg = calloc(1, sizeof(*reg));
+ if (reg == NULL) {
+ status = CELIX_ENOMEM;
+ } else {
+
+ reg->callback.handle = reg;
+ reg->callback.getUsingBundles = (void *)serviceRegistry_getUsingBundles;
+ reg->callback.unregister = (void *) serviceRegistry_unregisterService;
+ reg->callback.modified = (void *) serviceRegistry_servicePropertiesModified;
+
+ reg->serviceChanged = serviceChanged;
+ reg->serviceRegistrations = hashMap_create(NULL, NULL, NULL, NULL);
+ reg->framework = framework;
+ reg->currentServiceId = 1UL;
+ reg->serviceReferences = hashMap_create(NULL, NULL, NULL, NULL);
+
+ reg->checkDeletedReferences = CHECK_DELETED_REFERENCES;
+ reg->deletedServiceReferences = hashMap_create(NULL, NULL, NULL, NULL);
+
+ arrayList_create(®->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:dev@celix.apache.org">Apache Celix Project Team</a>
+ * \copyright Apache License, Version 2.0
+ */
+
+
+#ifndef SERVICE_REGISTRY_PRIVATE_H_
+#define SERVICE_REGISTRY_PRIVATE_H_
+
+#include "registry_callback_private.h"
+#include "service_registry.h"
+
+struct serviceRegistry {
+ framework_pt framework;
+ registry_callback_t callback;
+
+ hash_map_pt serviceRegistrations; //key = bundle (reg owner), value = list ( registration )
+ hash_map_pt serviceReferences; //key = bundle, value = map (key = serviceId, value = reference)
+
+ bool checkDeletedReferences; //If enabled. check if provided service references are still valid
+ hash_map_pt deletedServiceReferences; //key = ref pointer, value = bool
+
+ serviceChanged_function_pt serviceChanged;
+ unsigned long currentServiceId;
+
+ array_list_pt listenerHooks;
+
+ celix_thread_rwlock_t lock;
+};
+
+typedef enum reference_status_enum {
+ REF_ACTIVE,
+ REF_DELETED,
+ REF_UNKNOWN
+} reference_status_t;
+
+struct usageCount {
+ unsigned int count;
+ service_reference_pt reference;
+ void * service;
+ service_registration_pt registration;
+};
+
+typedef struct usageCount * usage_count_pt;
+
+#endif /* SERVICE_REGISTRY_PRIVATE_H_ */