| /** |
| *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); |
| |
| 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; |
| } |