http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/topology_manager/src/topology_manager.c ---------------------------------------------------------------------- diff --git a/bundles/remote_services/topology_manager/src/topology_manager.c b/bundles/remote_services/topology_manager/src/topology_manager.c new file mode 100644 index 0000000..2126df5 --- /dev/null +++ b/bundles/remote_services/topology_manager/src/topology_manager.c @@ -0,0 +1,985 @@ +/** + *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. + */ +/* + * topology_manager.c + * + * \date Sep 29, 2011 + * \author <a href="mailto:d...@celix.apache.org">Apache Celix Project Team</a> + * \copyright Apache License, Version 2.0 + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "celixbool.h" +#include "topology_manager.h" +#include "bundle_context.h" +#include "constants.h" +#include "bundle.h" +#include "remote_service_admin.h" +#include "remote_constants.h" +#include "filter.h" +#include "listener_hook_service.h" +#include "utils.h" +#include "service_reference.h" +#include "service_registration.h" +#include "log_service.h" +#include "log_helper.h" +#include "topology_manager.h" +#include "scope.h" +#include "hash_map.h" + +struct topology_manager { + bundle_context_pt context; + + celix_thread_mutex_t rsaListLock; + celix_thread_mutexattr_t rsaListLockAttr; + array_list_pt rsaList; + + celix_thread_mutex_t listenerListLock; + hash_map_pt listenerList; + + celix_thread_mutex_t exportedServicesLock; + hash_map_pt exportedServices; + + celix_thread_mutex_t importedServicesLock; + celix_thread_mutexattr_t importedServicesLockAttr; + hash_map_pt importedServices; + + scope_pt scope; + + log_helper_pt loghelper; +}; + +celix_status_t topologyManager_exportScopeChanged(void *handle, char *service_name); +celix_status_t topologyManager_importScopeChanged(void *handle, char *service_name); +celix_status_t topologyManager_notifyListenersEndpointAdded(topology_manager_pt manager, remote_service_admin_service_pt rsa, array_list_pt registrations); +celix_status_t topologyManager_notifyListenersEndpointRemoved(topology_manager_pt manager, remote_service_admin_service_pt rsa, export_registration_pt export); + +celix_status_t topologyManager_create(bundle_context_pt context, log_helper_pt logHelper, topology_manager_pt *manager, void **scope) { + celix_status_t status = CELIX_SUCCESS; + + *manager = calloc(1, sizeof(**manager)); + + if (!*manager) { + return CELIX_ENOMEM; + } + + (*manager)->context = context; + (*manager)->rsaList = NULL; + + arrayList_create(&(*manager)->rsaList); + + + celixThreadMutexAttr_create(&(*manager)->rsaListLockAttr); + celixThreadMutexAttr_settype(&(*manager)->rsaListLockAttr, CELIX_THREAD_MUTEX_RECURSIVE); + celixThreadMutex_create(&(*manager)->rsaListLock, &(*manager)->rsaListLockAttr); + + celixThreadMutexAttr_create(&(*manager)->importedServicesLockAttr); + celixThreadMutexAttr_settype(&(*manager)->importedServicesLockAttr, CELIX_THREAD_MUTEX_RECURSIVE); + celixThreadMutex_create(&(*manager)->importedServicesLock, &(*manager)->importedServicesLockAttr); + + celixThreadMutex_create(&(*manager)->exportedServicesLock, NULL); + celixThreadMutex_create(&(*manager)->listenerListLock, NULL); + + (*manager)->listenerList = hashMap_create(serviceReference_hashCode, NULL, serviceReference_equals2, NULL); + (*manager)->exportedServices = hashMap_create(serviceReference_hashCode, NULL, serviceReference_equals2, NULL); + (*manager)->importedServices = hashMap_create(NULL, NULL, NULL, NULL); + + status = scope_scopeCreate(*manager, &(*manager)->scope); + scope_setExportScopeChangedCallback((*manager)->scope, topologyManager_exportScopeChanged); + scope_setImportScopeChangedCallback((*manager)->scope, topologyManager_importScopeChanged); + *scope = (*manager)->scope; + + (*manager)->loghelper = logHelper; + + + return status; +} + +celix_status_t topologyManager_destroy(topology_manager_pt manager) { + celix_status_t status = CELIX_SUCCESS; + + celixThreadMutex_lock(&manager->listenerListLock); + hashMap_destroy(manager->listenerList, false, false); + + celixThreadMutex_unlock(&manager->listenerListLock); + celixThreadMutex_destroy(&manager->listenerListLock); + + celixThreadMutex_lock(&manager->rsaListLock); + + arrayList_destroy(manager->rsaList); + + celixThreadMutex_unlock(&manager->rsaListLock); + celixThreadMutex_destroy(&manager->rsaListLock); + celixThreadMutexAttr_destroy(&manager->rsaListLockAttr); + + celixThreadMutex_lock(&manager->exportedServicesLock); + + hashMap_destroy(manager->exportedServices, false, false); + + celixThreadMutex_unlock(&manager->exportedServicesLock); + celixThreadMutex_destroy(&manager->exportedServicesLock); + + celixThreadMutex_lock(&manager->importedServicesLock); + + hashMap_destroy(manager->importedServices, false, false); + + celixThreadMutex_unlock(&manager->importedServicesLock); + celixThreadMutex_destroy(&manager->importedServicesLock); + celixThreadMutexAttr_destroy(&manager->importedServicesLockAttr); + + scope_scopeDestroy(manager->scope); + free(manager); + + return status; +} + +celix_status_t topologyManager_closeImports(topology_manager_pt manager) { + celix_status_t status; + + status = celixThreadMutex_lock(&manager->importedServicesLock); + + hash_map_iterator_pt iter = hashMapIterator_create(manager->importedServices); + while (hashMapIterator_hasNext(iter)) { + hash_map_entry_pt entry = hashMapIterator_nextEntry(iter); + endpoint_description_pt ep = hashMapEntry_getKey(entry); + hash_map_pt imports = hashMapEntry_getValue(entry); + + if (imports != NULL) { + logHelper_log(manager->loghelper, OSGI_LOGSERVICE_INFO, "TOPOLOGY_MANAGER: Remove imported service (%s; %s).", ep->service, ep->id); + hash_map_iterator_pt importsIter = hashMapIterator_create(imports); + + while (hashMapIterator_hasNext(importsIter)) { + hash_map_entry_pt entry = hashMapIterator_nextEntry(importsIter); + + remote_service_admin_service_pt rsa = hashMapEntry_getKey(entry); + import_registration_pt import = hashMapEntry_getValue(entry); + + status = rsa->importRegistration_close(rsa->admin, import); + if (status == CELIX_SUCCESS) { + hashMapIterator_remove(importsIter); + } + } + hashMapIterator_destroy(importsIter); + + hashMapIterator_remove(iter); + + hashMap_destroy(imports, false, false); + } + } + hashMapIterator_destroy(iter); + + status = celixThreadMutex_unlock(&manager->importedServicesLock); + + return status; +} + +celix_status_t topologyManager_rsaAdding(void * handle, service_reference_pt reference, void **service) { + celix_status_t status; + topology_manager_pt manager = (topology_manager_pt) handle; + + status = bundleContext_getService(manager->context, reference, service); + + return status; +} + +celix_status_t topologyManager_rsaAdded(void * handle, service_reference_pt reference, void * service) { + celix_status_t status; + topology_manager_pt manager = (topology_manager_pt) handle; + properties_pt serviceProperties = NULL; + remote_service_admin_service_pt rsa = (remote_service_admin_service_pt) service; + logHelper_log(manager->loghelper, OSGI_LOGSERVICE_INFO, "TOPOLOGY_MANAGER: Added RSA"); + + status = celixThreadMutex_lock(&manager->rsaListLock); + + if (status == CELIX_SUCCESS) { + arrayList_add(manager->rsaList, rsa); + status = celixThreadMutex_unlock(&manager->rsaListLock); + } + + // add already imported services to new rsa + if (status == CELIX_SUCCESS) { + status = celixThreadMutex_lock(&manager->importedServicesLock); + + if (status == CELIX_SUCCESS) { + hash_map_iterator_pt importedServicesIterator = hashMapIterator_create(manager->importedServices); + + while (hashMapIterator_hasNext(importedServicesIterator)) { + hash_map_entry_pt entry = hashMapIterator_nextEntry(importedServicesIterator); + endpoint_description_pt endpoint = hashMapEntry_getKey(entry); + if (scope_allowImport(manager->scope, endpoint)) { + import_registration_pt import = NULL; + status = rsa->importService(rsa->admin, endpoint, &import); + + if (status == CELIX_SUCCESS) { + hash_map_pt imports = hashMapEntry_getValue(entry); + + if (imports == NULL) { + imports = hashMap_create(NULL, NULL, NULL, NULL); + hashMap_put(manager->importedServices,endpoint,imports); + } + + hashMap_put(imports, service, import); + } + } + } + + hashMapIterator_destroy(importedServicesIterator); + + celixThreadMutex_unlock(&manager->importedServicesLock); + } + } + + // add already exported services to new rsa + if (status == CELIX_SUCCESS) { + status = celixThreadMutex_lock(&manager->exportedServicesLock); + + if (status == CELIX_SUCCESS) { + hash_map_iterator_pt exportedServicesIterator = hashMapIterator_create(manager->exportedServices); + + while (hashMapIterator_hasNext(exportedServicesIterator)) { + hash_map_entry_pt entry = hashMapIterator_nextEntry(exportedServicesIterator); + service_reference_pt reference = hashMapEntry_getKey(entry); + const char* serviceId = NULL; + + serviceReference_getProperty(reference, OSGI_FRAMEWORK_SERVICE_ID, &serviceId); + + scope_getExportProperties(manager->scope, reference, &serviceProperties); + + array_list_pt endpoints = NULL; + status = rsa->exportService(rsa->admin, (char*)serviceId, serviceProperties, &endpoints); + + if (status == CELIX_SUCCESS) { + hash_map_pt exports = hashMapEntry_getValue(entry); + + if (exports == NULL) { + exports = hashMap_create(NULL, NULL, NULL, NULL); + hashMap_put(manager->exportedServices,reference,exports); + } + + hashMap_put(exports, rsa, endpoints); + status = topologyManager_notifyListenersEndpointAdded(manager, rsa, endpoints); + } + } + + hashMapIterator_destroy(exportedServicesIterator); + + celixThreadMutex_unlock(&manager->exportedServicesLock); + } + } + return status; +} + +celix_status_t topologyManager_rsaModified(void * handle, service_reference_pt reference, void * service) { + celix_status_t status = CELIX_SUCCESS; + + // Nop... + + return status; +} + +celix_status_t topologyManager_rsaRemoved(void * handle, service_reference_pt reference, void * service) { + celix_status_t status = CELIX_SUCCESS; + topology_manager_pt manager = (topology_manager_pt) handle; + remote_service_admin_service_pt rsa = (remote_service_admin_service_pt) service; + + if (celixThreadMutex_lock(&manager->exportedServicesLock) == CELIX_SUCCESS) { + hash_map_iterator_pt iter = hashMapIterator_create(manager->exportedServices); + + while (hashMapIterator_hasNext(iter)) { + + hash_map_entry_pt entry = hashMapIterator_nextEntry(iter); + service_reference_pt key = hashMapEntry_getKey(entry); + hash_map_pt exports = hashMapEntry_getValue(entry); + + /* + * the problem here is that also the rsa has a a list of + * endpoints which is destroyed when closing the exportRegistration + */ + array_list_pt exports_list = hashMap_get(exports, rsa); + + if (exports_list != NULL) { + int exportsIter = 0; + int exportListSize = arrayList_size(exports_list); + for (exportsIter = 0; exports_list != NULL && exportsIter < exportListSize; exportsIter++) { + export_registration_pt export = arrayList_get(exports_list, exportsIter); + topologyManager_notifyListenersEndpointRemoved(manager, rsa, export); + rsa->exportRegistration_close(rsa->admin, export); + } + } + + hashMap_remove(exports, rsa); + /*if(exports_list!=NULL){ + arrayList_destroy(exports_list); + }*/ + + if (hashMap_size(exports) == 0) { + hashMap_remove(manager->exportedServices, key); + hashMap_destroy(exports, false, false); + + hashMapIterator_destroy(iter); + iter = hashMapIterator_create(manager->exportedServices); + } + } + hashMapIterator_destroy(iter); + celixThreadMutex_unlock(&manager->exportedServicesLock); + } + + if (celixThreadMutex_lock(&manager->importedServicesLock) == CELIX_SUCCESS) { + hash_map_iterator_pt iter = hashMapIterator_create(manager->importedServices); + + while (hashMapIterator_hasNext(iter)) { + hash_map_entry_pt entry = hashMapIterator_nextEntry(iter); + hash_map_pt imports = hashMapEntry_getValue(entry); + + import_registration_pt import = hashMap_get(imports, rsa); + + if (import != NULL) { + celix_status_t subStatus = rsa->importRegistration_close(rsa->admin, import); + + if (subStatus == CELIX_SUCCESS) { + hashMap_remove(imports, rsa); + } else { + status = subStatus; + } + } + } + hashMapIterator_destroy(iter); + celixThreadMutex_unlock(&manager->importedServicesLock); + } + + if (celixThreadMutex_lock(&manager->rsaListLock) == CELIX_SUCCESS) { + arrayList_removeElement(manager->rsaList, rsa); + celixThreadMutex_unlock(&manager->rsaListLock); + } + + logHelper_log(manager->loghelper, OSGI_LOGSERVICE_INFO, "TOPOLOGY_MANAGER: Removed RSA"); + + return status; +} + + +celix_status_t topologyManager_serviceChanged(void *listener, service_event_pt event) { + celix_status_t status = CELIX_SUCCESS; + service_listener_pt listen = listener; + topology_manager_pt manager = listen->handle; + + const char* export = NULL; + const char* serviceId = NULL; + serviceReference_getProperty(event->reference, OSGI_RSA_SERVICE_EXPORTED_INTERFACES, &export); + serviceReference_getProperty(event->reference, OSGI_FRAMEWORK_SERVICE_ID, &serviceId); + + if (!export) { + // Nothing needs to be done: we're not interested... + return status; + } + + switch (event->type) { + case OSGI_FRAMEWORK_SERVICE_EVENT_REGISTERED: + status = topologyManager_addExportedService(manager, event->reference, (char*)serviceId); + break; + case OSGI_FRAMEWORK_SERVICE_EVENT_MODIFIED: + status = topologyManager_removeExportedService(manager, event->reference, (char*)serviceId); + + if (status == CELIX_SUCCESS) { + status = topologyManager_addExportedService(manager, event->reference, (char*)serviceId); + } + break; + case OSGI_FRAMEWORK_SERVICE_EVENT_UNREGISTERING: + status = topologyManager_removeExportedService(manager, event->reference, (char*)serviceId); + break; + case OSGI_FRAMEWORK_SERVICE_EVENT_MODIFIED_ENDMATCH: + break; + } + + return status; +} + +celix_status_t topologyManager_exportScopeChanged(void *handle, char *filterStr) { + celix_status_t status = CELIX_SUCCESS; + topology_manager_pt manager = (topology_manager_pt) handle; + service_registration_pt reg = NULL; + const char* serviceId = NULL; + bool found; + properties_pt props; + filter_pt filter = filter_create(filterStr); + + if (filter == NULL) { + printf("filter creating failed\n"); + return CELIX_ENOMEM; + } + + // add already exported services to new rsa + if (celixThreadMutex_lock(&manager->exportedServicesLock) == CELIX_SUCCESS) { + hash_map_iterator_pt exportedServicesIterator = hashMapIterator_create(manager->exportedServices); + int size = hashMap_size(manager->exportedServices); + service_reference_pt *srvRefs = (service_reference_pt *) calloc(size, sizeof(service_reference_pt)); + char **srvIds = (char **) calloc(size, sizeof(char*)); + int nrFound = 0; + + found = false; + + while (hashMapIterator_hasNext(exportedServicesIterator)) { + hash_map_entry_pt entry = hashMapIterator_nextEntry(exportedServicesIterator); + service_reference_pt reference = hashMapEntry_getKey(entry); + reg = NULL; + serviceReference_getServiceRegistration(reference, ®); + if (reg != NULL) { + props = NULL; + serviceRegistration_getProperties(reg, &props); + status = filter_match(filter, props, &found); + if (found) { + srvRefs[nrFound] = reference; + serviceReference_getProperty(reference, OSGI_FRAMEWORK_SERVICE_ID, &serviceId); + srvIds[nrFound++] = (char*)serviceId; + } + } + } + + hashMapIterator_destroy(exportedServicesIterator); + celixThreadMutex_unlock(&manager->exportedServicesLock); + + if (nrFound > 0) { + for (int i = 0; i < nrFound; i++) { + // Question: can srvRefs become invalid meanwhile?? + const char* export = NULL; + serviceReference_getProperty(srvRefs[i], (char *) OSGI_RSA_SERVICE_EXPORTED_INTERFACES, &export); + + if (export) { + celix_status_t substatus = topologyManager_removeExportedService(manager, srvRefs[i], srvIds[i]); + + if (substatus != CELIX_SUCCESS) { + logHelper_log(manager->loghelper, OSGI_LOGSERVICE_ERROR, "TOPOLOGY_MANAGER: Removal of exported service (%s) failed.", srvIds[i]); + } else { + substatus = topologyManager_addExportedService(manager, srvRefs[i], srvIds[i]); + } + + if (substatus != CELIX_SUCCESS) { + status = substatus; + } + } + } + } + + free(srvRefs); + free(srvIds); + } + + filter_destroy(filter); + + return status; +} + +celix_status_t topologyManager_importScopeChanged(void *handle, char *service_name) { + celix_status_t status = CELIX_SUCCESS; + endpoint_description_pt endpoint; + topology_manager_pt manager = (topology_manager_pt) handle; + bool found = false; + + // add already exported services to new rsa + if (celixThreadMutex_lock(&manager->importedServicesLock) == CELIX_SUCCESS) { + hash_map_iterator_pt importedServicesIterator = hashMapIterator_create(manager->importedServices); + while (!found && hashMapIterator_hasNext(importedServicesIterator)) { + hash_map_entry_pt entry = hashMapIterator_nextEntry(importedServicesIterator); + endpoint = hashMapEntry_getKey(entry); + + entry = hashMap_getEntry(endpoint->properties, (void *) OSGI_FRAMEWORK_OBJECTCLASS); + char* name = (char *) hashMapEntry_getValue(entry); + // Test if a service with the same name is imported + if (strcmp(name, service_name) == 0) { + found = true; + } + } + hashMapIterator_destroy(importedServicesIterator); + celixThreadMutex_unlock(&manager->importedServicesLock); + } + + if (found) { + status = topologyManager_removeImportedService(manager, endpoint, NULL); + + if (status != CELIX_SUCCESS) { + logHelper_log(manager->loghelper, OSGI_LOGSERVICE_ERROR, "TOPOLOGY_MANAGER: Removal of imported service (%s; %s) failed.", endpoint->service, endpoint->id); + } else { + status = topologyManager_addImportedService(manager, endpoint, NULL); + } + } + return status; +} + +celix_status_t topologyManager_addImportedService(void *handle, endpoint_description_pt endpoint, char *matchedFilter) { + celix_status_t status = CELIX_SUCCESS; + topology_manager_pt manager = handle; + + logHelper_log(manager->loghelper, OSGI_LOGSERVICE_INFO, "TOPOLOGY_MANAGER: Add imported service (%s; %s).", endpoint->service, endpoint->id); + + if (celixThreadMutex_lock(&manager->importedServicesLock) == CELIX_SUCCESS) { + + hash_map_pt imports = hashMap_create(NULL, NULL, NULL, NULL); + hashMap_put(manager->importedServices, endpoint, imports); + + if (scope_allowImport(manager->scope, endpoint)) { + if (celixThreadMutex_lock(&manager->rsaListLock) == CELIX_SUCCESS) { + int size = arrayList_size(manager->rsaList); + + for (int iter = 0; iter < size; iter++) { + import_registration_pt import = NULL; + remote_service_admin_service_pt rsa = arrayList_get(manager->rsaList, iter); + celix_status_t substatus = rsa->importService(rsa->admin, endpoint, &import); + if (substatus == CELIX_SUCCESS) { + hashMap_put(imports, rsa, import); + } else { + status = substatus; + } + } + celixThreadMutex_unlock(&manager->rsaListLock); + } + + } + + celixThreadMutex_unlock(&manager->importedServicesLock); + } + + + return status; +} + +celix_status_t topologyManager_removeImportedService(void *handle, endpoint_description_pt endpoint, char *matchedFilter) { + celix_status_t status = CELIX_SUCCESS; + topology_manager_pt manager = handle; + + logHelper_log(manager->loghelper, OSGI_LOGSERVICE_INFO, "TOPOLOGY_MANAGER: Remove imported service (%s; %s).", endpoint->service, endpoint->id); + + if (celixThreadMutex_lock(&manager->importedServicesLock) == CELIX_SUCCESS) { + + hash_map_iterator_pt iter = hashMapIterator_create(manager->importedServices); + while (hashMapIterator_hasNext(iter)) { + hash_map_entry_pt entry = hashMapIterator_nextEntry(iter); + endpoint_description_pt ep = hashMapEntry_getKey(entry); + hash_map_pt imports = hashMapEntry_getValue(entry); + + if (imports != NULL && strcmp(endpoint->id, ep->id) == 0) { + hash_map_iterator_pt importsIter = hashMapIterator_create(imports); + + while (hashMapIterator_hasNext(importsIter)) { + hash_map_entry_pt entry = hashMapIterator_nextEntry(importsIter); + remote_service_admin_service_pt rsa = hashMapEntry_getKey(entry); + import_registration_pt import = hashMapEntry_getValue(entry); + celix_status_t substatus = rsa->importRegistration_close(rsa->admin, import); + if (substatus == CELIX_SUCCESS) { + hashMapIterator_remove(importsIter); + } else { + status = substatus; + } + } + hashMapIterator_destroy(importsIter); + hashMapIterator_remove(iter); + + hashMap_destroy(imports, false, false); + } + } + hashMapIterator_destroy(iter); + celixThreadMutex_unlock(&manager->importedServicesLock); + } + + return status; +} + +celix_status_t topologyManager_addExportedService(topology_manager_pt manager, service_reference_pt reference, char *serviceId) { + celix_status_t status = CELIX_SUCCESS; + properties_pt serviceProperties = NULL; + + logHelper_log(manager->loghelper, OSGI_LOGSERVICE_INFO, "TOPOLOGY_MANAGER: Add exported service (%s).", serviceId); + + if (celixThreadMutex_lock(&manager->exportedServicesLock) == CELIX_SUCCESS) { + scope_getExportProperties(manager->scope, reference, &serviceProperties); + hash_map_pt exports = hashMap_create(NULL, NULL, NULL, NULL); + hashMap_put(manager->exportedServices, reference, exports); + + if (celixThreadMutex_lock(&manager->rsaListLock) == CELIX_SUCCESS) { + int size = arrayList_size(manager->rsaList); + + if (size == 0) { + logHelper_log(manager->loghelper, OSGI_LOGSERVICE_WARNING, "TOPOLOGY_MANAGER: No RSA available yet."); + } + + for (int iter = 0; iter < size; iter++) { + remote_service_admin_service_pt rsa = arrayList_get(manager->rsaList, iter); + + array_list_pt endpoints = NULL; + celix_status_t substatus = rsa->exportService(rsa->admin, serviceId, serviceProperties, &endpoints); + + if (substatus == CELIX_SUCCESS) { + hashMap_put(exports, rsa, endpoints); + topologyManager_notifyListenersEndpointAdded(manager, rsa, endpoints); + } else { + status = substatus; + } + } + celixThreadMutex_unlock(&manager->rsaListLock); + } + celixThreadMutex_unlock(&manager->exportedServicesLock); + } + + return status; +} + +celix_status_t topologyManager_removeExportedService(topology_manager_pt manager, service_reference_pt reference, char *serviceId) { + celix_status_t status = CELIX_SUCCESS; + + logHelper_log(manager->loghelper, OSGI_LOGSERVICE_INFO, "TOPOLOGY_MANAGER: Remove exported service (%s).", serviceId); + + if (celixThreadMutex_lock(&manager->exportedServicesLock) == CELIX_SUCCESS) { + hash_map_pt exports = hashMap_get(manager->exportedServices, reference); + if (exports) { + hash_map_iterator_pt iter = hashMapIterator_create(exports); + while (hashMapIterator_hasNext(iter)) { + hash_map_entry_pt entry = hashMapIterator_nextEntry(iter); + remote_service_admin_service_pt rsa = hashMapEntry_getKey(entry); + array_list_pt exportRegistrations = hashMapEntry_getValue(entry); + + int size = arrayList_size(exportRegistrations); + + for (int exportsIter = 0; exportsIter < size; exportsIter++) { + export_registration_pt export = arrayList_get(exportRegistrations, exportsIter); + topologyManager_notifyListenersEndpointRemoved(manager, rsa, export); + rsa->exportRegistration_close(rsa->admin, export); + } + + hashMap_remove(exports, rsa); + //arrayList_destroy(exportRegistrations); + hashMapIterator_destroy(iter); + iter = hashMapIterator_create(exports); + + } + hashMapIterator_destroy(iter); + } + exports = hashMap_remove(manager->exportedServices, reference); + + if (exports != NULL) { + hashMap_destroy(exports, false, false); + } + + celixThreadMutex_unlock(&manager->exportedServicesLock); + } + + return status; +} + +celix_status_t topologyManager_getEndpointDescriptionForExportRegistration(remote_service_admin_service_pt rsa, export_registration_pt export, endpoint_description_pt *endpoint) { + celix_status_t status; + + export_reference_pt reference = NULL; + status = rsa->exportRegistration_getExportReference(export, &reference); + + if (status == CELIX_SUCCESS) { + status = rsa->exportReference_getExportedEndpoint(reference, endpoint); + } + + free(reference); + + return status; +} + +celix_status_t topologyManager_endpointListenerAdding(void* handle, service_reference_pt reference, void** service) { + celix_status_t status = CELIX_SUCCESS; + topology_manager_pt manager = (topology_manager_pt) handle; + + bundleContext_getService(manager->context, reference, service); + + return status; +} + +celix_status_t topologyManager_endpointListenerAdded(void* handle, service_reference_pt reference, void* service) { + celix_status_t status = CELIX_SUCCESS; + topology_manager_pt manager = handle; + const char* scope = NULL; + + logHelper_log(manager->loghelper, OSGI_LOGSERVICE_INFO, "TOPOLOGY_MANAGER: Added ENDPOINT_LISTENER"); + + if (celixThreadMutex_lock(&manager->listenerListLock) == CELIX_SUCCESS) { + hashMap_put(manager->listenerList, reference, NULL); + celixThreadMutex_unlock(&manager->listenerListLock); + + serviceReference_getProperty(reference, OSGI_ENDPOINT_LISTENER_SCOPE, &scope); + + filter_pt filter = filter_create(scope); + hash_map_iterator_pt refIter = hashMapIterator_create(manager->exportedServices); + + while (hashMapIterator_hasNext(refIter)) { + hash_map_pt rsaExports = hashMapIterator_nextValue(refIter); + hash_map_iterator_pt rsaIter = hashMapIterator_create(rsaExports); + + while (hashMapIterator_hasNext(rsaIter)) { + hash_map_entry_pt entry = hashMapIterator_nextEntry(rsaIter); + remote_service_admin_service_pt rsa = hashMapEntry_getKey(entry); + array_list_pt registrations = hashMapEntry_getValue(entry); + + int arrayListSize = arrayList_size(registrations); + int cnt = 0; + + for (; cnt < arrayListSize; cnt++) { + export_registration_pt export = arrayList_get(registrations, cnt); + endpoint_description_pt endpoint = NULL; + + status = topologyManager_getEndpointDescriptionForExportRegistration(rsa, export, &endpoint); + if (status == CELIX_SUCCESS) { + bool matchResult = false; + filter_match(filter, endpoint->properties, &matchResult); + if (matchResult) { + endpoint_listener_pt listener = (endpoint_listener_pt) service; + status = listener->endpointAdded(listener->handle, endpoint, (char*)scope); + } + } + } + } + hashMapIterator_destroy(rsaIter); + } + hashMapIterator_destroy(refIter); + + filter_destroy(filter); + } + + return status; +} + +celix_status_t topologyManager_endpointListenerModified(void * handle, service_reference_pt reference, void * service) { + celix_status_t status; + + status = topologyManager_endpointListenerRemoved(handle, reference, service); + + if (status == CELIX_SUCCESS) { + status = topologyManager_endpointListenerAdded(handle, reference, service); + } + + return status; +} + +celix_status_t topologyManager_endpointListenerRemoved(void * handle, service_reference_pt reference, void * service) { + celix_status_t status = CELIX_SUCCESS; + topology_manager_pt manager = handle; + + if (celixThreadMutex_lock(&manager->listenerListLock) == CELIX_SUCCESS) { + + if (hashMap_remove(manager->listenerList, reference)) { + logHelper_log(manager->loghelper, OSGI_LOGSERVICE_INFO, "EndpointListener Removed"); + } + + celixThreadMutex_unlock(&manager->listenerListLock); + } + + return status; +} + +celix_status_t topologyManager_notifyListenersEndpointAdded(topology_manager_pt manager, remote_service_admin_service_pt rsa, array_list_pt registrations) { + celix_status_t status = CELIX_SUCCESS; + + if (celixThreadMutex_lock(&manager->listenerListLock) == CELIX_SUCCESS) { + + hash_map_iterator_pt iter = hashMapIterator_create(manager->listenerList); + while (hashMapIterator_hasNext(iter)) { + const char* scope = NULL; + endpoint_listener_pt epl = NULL; + service_reference_pt reference = hashMapIterator_nextKey(iter); + + serviceReference_getProperty(reference, OSGI_ENDPOINT_LISTENER_SCOPE, &scope); + + status = bundleContext_getService(manager->context, reference, (void **) &epl); + if (status == CELIX_SUCCESS) { + filter_pt filter = filter_create(scope); + + int regSize = arrayList_size(registrations); + for (int regIt = 0; regIt < regSize; regIt++) { + export_registration_pt export = arrayList_get(registrations, regIt); + endpoint_description_pt endpoint = NULL; + celix_status_t substatus = topologyManager_getEndpointDescriptionForExportRegistration(rsa, export, &endpoint); + if (substatus == CELIX_SUCCESS) { + bool matchResult = false; + filter_match(filter, endpoint->properties, &matchResult); + if (matchResult) { + status = epl->endpointAdded(epl->handle, endpoint, (char*)scope); + } + } else { + status = substatus; + } + } + filter_destroy(filter); + } + } + hashMapIterator_destroy(iter); + celixThreadMutex_unlock(&manager->listenerListLock); + } + + return status; +} + +celix_status_t topologyManager_notifyListenersEndpointRemoved(topology_manager_pt manager, remote_service_admin_service_pt rsa, export_registration_pt export) { + celix_status_t status = CELIX_SUCCESS; + + if (celixThreadMutex_lock(&manager->listenerListLock) == CELIX_SUCCESS) { + hash_map_iterator_pt iter = hashMapIterator_create(manager->listenerList); + while (hashMapIterator_hasNext(iter)) { + endpoint_description_pt endpoint = NULL; + endpoint_listener_pt epl = NULL; + celix_status_t substatus; + const char* scope = NULL; + + service_reference_pt reference = hashMapIterator_nextKey(iter); + serviceReference_getProperty(reference, OSGI_ENDPOINT_LISTENER_SCOPE, &scope); + + substatus = bundleContext_getService(manager->context, reference, (void **) &epl); + + if (substatus == CELIX_SUCCESS) { + substatus = topologyManager_getEndpointDescriptionForExportRegistration(rsa, export, &endpoint); + } + + if (substatus == CELIX_SUCCESS) { + substatus = epl->endpointRemoved(epl->handle, endpoint, NULL); + } + + /* if (substatus != CELIX_SUCCESS) { + status = substatus; + + } + */ + } + hashMapIterator_destroy(iter); + celixThreadMutex_unlock(&manager->listenerListLock); + } + + return status; +} + +static celix_status_t topologyManager_extendFilter(topology_manager_pt manager, const char *filter, char **updatedFilter) { + celix_status_t status; + bundle_context_pt context = manager->context; + const char* uuid = NULL; + + status = bundleContext_getProperty(context, OSGI_FRAMEWORK_FRAMEWORK_UUID, &uuid); + + if (!uuid) { + logHelper_log(manager->loghelper, OSGI_LOGSERVICE_ERROR, "TOPOLOGY_MANAGER: no framework UUID defined?!"); + return CELIX_BUNDLE_EXCEPTION; + } + + int len = 10 + strlen(filter) + strlen(OSGI_RSA_ENDPOINT_FRAMEWORK_UUID) + strlen(uuid); + *updatedFilter = malloc(len); + if (!*updatedFilter) { + return CELIX_ENOMEM; + } + + snprintf(*updatedFilter, len, "(&%s(!(%s=%s)))", filter, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, uuid); + + return status; +} + +celix_status_t topologyManager_listenerAdded(void *handle, array_list_pt listeners) { + celix_status_t status = CELIX_SUCCESS; + topology_manager_pt manager = handle; + + for (int i = 0; i < arrayList_size(listeners); i++) { + listener_hook_info_pt info = arrayList_get(listeners, i); + bundle_pt bundle = NULL, self = NULL; + bundleContext_getBundle(info->context, &bundle); + bundleContext_getBundle(manager->context, &self); + if (bundle == self) { + logHelper_log(manager->loghelper, OSGI_LOGSERVICE_DEBUG, "TOPOLOGY_MANAGER: Ignore myself."); + continue; + } + + logHelper_log(manager->loghelper, OSGI_LOGSERVICE_INFO, "TOPOLOGY_MANAGER: listener with filter \"%s\" added", info->filter); + + char *filter = NULL; + bool free_filter = true; + status = topologyManager_extendFilter(manager, info->filter, &filter); +#if 0 + if(filter != NULL){ + // TODO: add status handling + status = celixThreadMutex_lock(&manager->importScopesLock); + + struct scope *interest = hashMap_get(manager->importScopes, filter); + if (interest) { + interest->refs++; + free(filter); + filter = NULL; + } else { + interest = malloc(sizeof(*interest)); + interest->filter = filter; + interest->refs = 1; + hashMap_put(manager->importScopes, filter, interest); + free_filter = false; + } + + status = celixThreadMutex_unlock(&manager->importScopesLock); + } +#endif + + if (filter != NULL && free_filter) { + free(filter); + } + + } + + return status; +} + +celix_status_t topologyManager_listenerRemoved(void *handle, array_list_pt listeners) { + celix_status_t status = CELIX_SUCCESS; + topology_manager_pt manager = handle; + + for (int i = 0; i < arrayList_size(listeners); i++) { + listener_hook_info_pt info = arrayList_get(listeners, i); + + bundle_pt bundle = NULL, self = NULL; + bundleContext_getBundle(info->context, &bundle); + bundleContext_getBundle(manager->context, &self); + if (bundle == self) { + logHelper_log(manager->loghelper, OSGI_LOGSERVICE_DEBUG, "TOPOLOGY_MANAGER: Ignore myself."); + continue; + } + + logHelper_log(manager->loghelper, OSGI_LOGSERVICE_INFO, "TOPOLOGY_MANAGER: listener with filter \"%s\" removed.", info->filter); + + char *filter = NULL; + topologyManager_extendFilter(manager, info->filter, &filter); +#if 0 + status = celixThreadMutex_lock(&manager->importScopesLock); + + struct scope *interest = hashMap_get(manager->importScopes, filter); + if (interest != NULL && --interest->refs <= 0) { + // last reference, remove from scope + hash_map_entry_pt entry = hashMap_getEntry(manager->importScopes, filter); + char* key = (char*) hashMapEntry_getKey(entry); + interest = hashMap_remove(manager->importScopes, filter); + free(key); + free(interest); + } +#endif + + if (filter != NULL) { + free(filter); + } +#if 0 + status = celixThreadMutex_unlock(&manager->importScopesLock); +#endif + } + + return status; +} +
http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/topology_manager/src/topology_manager.h ---------------------------------------------------------------------- diff --git a/bundles/remote_services/topology_manager/src/topology_manager.h b/bundles/remote_services/topology_manager/src/topology_manager.h new file mode 100644 index 0000000..b6ee064 --- /dev/null +++ b/bundles/remote_services/topology_manager/src/topology_manager.h @@ -0,0 +1,66 @@ +/** + *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. + */ +/* + * topology_manager.h + * + * \date Sep 29, 2011 + * \author <a href="mailto:d...@celix.apache.org">Apache Celix Project Team</a> + * \copyright Apache License, Version 2.0 + */ + +#ifndef TOPOLOGY_MANAGER_H_ +#define TOPOLOGY_MANAGER_H_ + +#include "endpoint_listener.h" +#include "service_reference.h" +#include "bundle_context.h" +#include "log_helper.h" +#include "scope.h" + +#define OSGI_RSA_REMOTE_SERVICE_ADMIN "remote_service_admin" + +typedef struct topology_manager topology_manager_t; +typedef struct topology_manager *topology_manager_pt; + +celix_status_t topologyManager_create(bundle_context_pt context, log_helper_pt logHelper, topology_manager_pt *manager, void **scope); +celix_status_t topologyManager_destroy(topology_manager_pt manager); +celix_status_t topologyManager_closeImports(topology_manager_pt manager); + +celix_status_t topologyManager_rsaAdding(void *handle, service_reference_pt reference, void **service); +celix_status_t topologyManager_rsaAdded(void *handle, service_reference_pt reference, void *service); +celix_status_t topologyManager_rsaModified(void *handle, service_reference_pt reference, void *service); +celix_status_t topologyManager_rsaRemoved(void *handle, service_reference_pt reference, void *service); + +celix_status_t topologyManager_endpointListenerAdding(void* handle, service_reference_pt reference, void** service); +celix_status_t topologyManager_endpointListenerAdded(void* handle, service_reference_pt reference, void* service); +celix_status_t topologyManager_endpointListenerModified(void * handle, service_reference_pt reference, void* service); +celix_status_t topologyManager_endpointListenerRemoved(void * handle, service_reference_pt reference, void* service); + +celix_status_t topologyManager_serviceChanged(void *listener, service_event_pt event); + +celix_status_t topologyManager_addImportedService(void *handle, endpoint_description_pt endpoint, char *matchedFilter); +celix_status_t topologyManager_removeImportedService(void *handle, endpoint_description_pt endpoint, char *matchedFilter); + +celix_status_t topologyManager_addExportedService(topology_manager_pt manager, service_reference_pt reference, char *serviceId); +celix_status_t topologyManager_removeExportedService(topology_manager_pt manager, service_reference_pt reference, char *serviceId); + +celix_status_t topologyManager_listenerAdded(void *handle, array_list_pt listeners); +celix_status_t topologyManager_listenerRemoved(void *handle, array_list_pt listeners); + +#endif /* TOPOLOGY_MANAGER_H_ */ http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/topology_manager/tms_tst/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/bundles/remote_services/topology_manager/tms_tst/CMakeLists.txt b/bundles/remote_services/topology_manager/tms_tst/CMakeLists.txt new file mode 100644 index 0000000..fc0a016 --- /dev/null +++ b/bundles/remote_services/topology_manager/tms_tst/CMakeLists.txt @@ -0,0 +1,75 @@ +# 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. + + +include_directories( + ${PROJECT_SOURCE_DIR}/framework/public/include + ${PROJECT_SOURCE_DIR}/utils/public/include + ${PROJECT_SOURCE_DIR}/utils/public/include + ${PROJECT_SOURCE_DIR}/remote_services/remote_service_admin/public/include + ${PROJECT_SOURCE_DIR}/remote_services/examples/calculator_service/public/include + disc_mock + bundle +) + +add_subdirectory(bundle) +add_subdirectory(disc_mock) + +#SET(CMAKE_SKIP_BUILD_RPATH FALSE) #TODO needed? +#SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) #TODO needed? +#SET(CMAKE_INSTALL_RPATH "${PROJECT_BINARY_DIR}/framework" "${PROJECT_BINARY_DIR}/utils" "${PROJECT_BINARY_DIR}/dfi") + +add_executable(test_tm_scoped + run_tests.cpp + tms_tests.cpp +) +target_include_directories(test_tm_scoped PRIVATE ../src ../include) +target_link_libraries(test_tm_scoped PRIVATE + Celix::framework + ${CPPUTEST_LIBRARY} + ${JANSSON_LIBRARY} + calculator_api + Celix::rsa_common +) + +add_dependencies(test_tm_scoped rsa_dfi_bundle rsa_topology_manager_bundle) + +file(GENERATE + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/config.properties" + CONTENT " +cosgi.auto.start.1=$<TARGET_PROPERTY:Celix::rsa_dfi,BUNDLE_FILE> $<TARGET_PROPERTY:calculator,BUNDLE_FILE> $<TARGET_PROPERTY:Celix::rsa_topology_manager,BUNDLE_FILE> $<TARGET_PROPERTY:topology_manager_disc_mock_bundle,BUNDLE_FILE> +LOGHELPER_ENABLE_STDOUT_FALLBACK=true +org.osgi.framework.storage.clean=onFirstInit +") + +file(GENERATE + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/config_import.properties" + CONTENT " +cosgi.auto.start.1=$<TARGET_PROPERTY:Celix::rsa_dfi,BUNDLE_FILE> $<TARGET_PROPERTY:calculator,BUNDLE_FILE> $<TARGET_PROPERTY:Celix::rsa_topology_manager,BUNDLE_FILE> $<TARGET_PROPERTY:topology_manager_test_bundle,BUNDLE_FILE> +LOGHELPER_ENABLE_STDOUT_FALLBACK=true +org.osgi.framework.storage.clean=onFirstInit +") + +configure_file("scope.json" "scope.json") +configure_file("scope2.json" "scope2.json") +configure_file("scope3.json" "scope3.json") +configure_file("scope4.json" "scope4.json") + + +add_test(NAME run_test_tm_scoped COMMAND test_tm_scoped) +SETUP_TARGET_FOR_COVERAGE(test_tm_scoped_cov test_tm_scoped ${CMAKE_BINARY_DIR}/coverage/test_tm_scoped/test_tm_scoped) + http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/topology_manager/tms_tst/bundle/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/bundles/remote_services/topology_manager/tms_tst/bundle/CMakeLists.txt b/bundles/remote_services/topology_manager/tms_tst/bundle/CMakeLists.txt new file mode 100644 index 0000000..15536e0 --- /dev/null +++ b/bundles/remote_services/topology_manager/tms_tst/bundle/CMakeLists.txt @@ -0,0 +1,35 @@ +# 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. + + +include_directories( + ${CPPUTEST_INCLUDE_DIR} + ${PROJECT_SOURCE_DIR}/framework/public/include + ${PROJECT_SOURCE_DIR}/utils/public/include +) + +add_celix_bundle(topology_manager_test_bundle + VERSION 0.0.1 + SOURCES + tst_activator.c +) +celix_bundle_files(topology_manager_test_bundle + org.apache.celix.test.MyBundle.descriptor + DESTINATION . +) + +target_link_libraries(topology_manager_test_bundle PRIVATE ${CPPUTEST_LIBRARY} Celix::rsa_spi calculator_api) http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/topology_manager/tms_tst/bundle/org.apache.celix.test.MyBundle.descriptor ---------------------------------------------------------------------- diff --git a/bundles/remote_services/topology_manager/tms_tst/bundle/org.apache.celix.test.MyBundle.descriptor b/bundles/remote_services/topology_manager/tms_tst/bundle/org.apache.celix.test.MyBundle.descriptor new file mode 100644 index 0000000..8f04454 --- /dev/null +++ b/bundles/remote_services/topology_manager/tms_tst/bundle/org.apache.celix.test.MyBundle.descriptor @@ -0,0 +1,9 @@ +:header +type=interface +name=MyBundle +version=1.0.0 +:annotations +classname=org.apache.celix.MyBundle +:types +:methods +add(DD)D=add(#am=handle;PDD#am=pre;*D)N http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/topology_manager/tms_tst/bundle/tst_activator.c ---------------------------------------------------------------------- diff --git a/bundles/remote_services/topology_manager/tms_tst/bundle/tst_activator.c b/bundles/remote_services/topology_manager/tms_tst/bundle/tst_activator.c new file mode 100644 index 0000000..dc5dcfc --- /dev/null +++ b/bundles/remote_services/topology_manager/tms_tst/bundle/tst_activator.c @@ -0,0 +1,141 @@ +/* + *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. + */ +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <service_tracker_customizer.h> +#include <service_tracker.h> + +#include "bundle_activator.h" +#include "bundle_context.h" +#include "service_registration.h" +#include "service_reference.h" +#include "celix_errno.h" + +#include "tst_service.h" +#include "calculator_service.h" + +#define IMPORT_SERVICE_NAME "org.apache.celix.test.MyBundle" // see TmsTest.cpp + +struct activator { + bundle_context_pt context; + struct tst_service serv; + service_registration_pt reg; + + service_tracker_customizer_pt cust; + service_tracker_pt tracker; + tst_service_pt *import; // MyBundle service pointer +}; + +static celix_status_t addImport(void * handle, service_reference_pt reference, void * service); +static celix_status_t removeImport(void * handle, service_reference_pt reference, void * service); + +static bool IsImported(void *handle); + +celix_status_t bundleActivator_create(bundle_context_pt context, void **out) { + celix_status_t status = CELIX_SUCCESS; + struct activator *act = calloc(1, sizeof(*act)); + if (act != NULL) { + act->context = context; + act->serv.handle = act; + act->serv.IsImported = IsImported; + act->import = NULL; + + status = serviceTrackerCustomizer_create(act, NULL, addImport, NULL, removeImport, &act->cust); + status = CELIX_DO_IF(status, serviceTracker_create(context, IMPORT_SERVICE_NAME, act->cust, &act->tracker)); + + } else { + status = CELIX_ENOMEM; + } + + if (status == CELIX_SUCCESS) { + *out = act; + } else if (act != NULL) { + if (act->cust != NULL) { + free(act->cust); + act->cust = NULL; + } + if (act->tracker != NULL) { + serviceTracker_destroy(act->tracker); + act->tracker = NULL; + } + free(act); + } + + return CELIX_SUCCESS; +} + +static celix_status_t addImport(void * handle, service_reference_pt reference, void * service) { + celix_status_t status = CELIX_SUCCESS; + struct activator * act = handle; + act->import = service; + return status; +} + +static celix_status_t removeImport(void * handle, service_reference_pt reference, void * service) { + celix_status_t status = CELIX_SUCCESS; + struct activator * act = handle; + if (act->import == service) { + act->import = NULL; + } + return status; + +} + +celix_status_t bundleActivator_start(void * userData, bundle_context_pt context) { + celix_status_t status; + struct activator * act = userData; + + act->reg = NULL; + status = bundleContext_registerService(context, (char *) TST_SERVICE_NAME, &act->serv, NULL, &act->reg); + + status = CELIX_DO_IF(status, serviceTracker_open(act->tracker)); + + return status; +} + +celix_status_t bundleActivator_stop(void * userData, bundle_context_pt context) { + celix_status_t status; + struct activator * act = userData; + + status = serviceRegistration_unregister(act->reg); + status = CELIX_DO_IF(status, serviceTracker_close(act->tracker)); + + return status; +} + +celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt context) { + struct activator *act = userData; + if (act != NULL) { + if (act->tracker != NULL) { + serviceTracker_destroy(act->tracker); + act->tracker = NULL; + } + free(act); + } + return CELIX_SUCCESS; +} + +static bool IsImported(void *handle) { + + tst_service_pt service = (tst_service_pt) handle; + struct activator *act = (struct activator *) service->handle; + + return (act->import != NULL); +} http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/topology_manager/tms_tst/bundle/tst_service.h ---------------------------------------------------------------------- diff --git a/bundles/remote_services/topology_manager/tms_tst/bundle/tst_service.h b/bundles/remote_services/topology_manager/tms_tst/bundle/tst_service.h new file mode 100644 index 0000000..0f43cff --- /dev/null +++ b/bundles/remote_services/topology_manager/tms_tst/bundle/tst_service.h @@ -0,0 +1,32 @@ +/* + *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. + */ + +#ifndef CELIX_TST_SERVICE_H +#define CELIX_TST_SERVICE_H + +#define TST_SERVICE_NAME "tst_service" + +struct tst_service { + void *handle; + bool (*IsImported)(void *handle); +}; + +typedef struct tst_service *tst_service_pt; + +#endif //CELIX_TST_SERVICE_H http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/topology_manager/tms_tst/disc_mock/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/bundles/remote_services/topology_manager/tms_tst/disc_mock/CMakeLists.txt b/bundles/remote_services/topology_manager/tms_tst/disc_mock/CMakeLists.txt new file mode 100644 index 0000000..6b8ae43 --- /dev/null +++ b/bundles/remote_services/topology_manager/tms_tst/disc_mock/CMakeLists.txt @@ -0,0 +1,28 @@ +# 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. + +add_celix_bundle(topology_manager_disc_mock_bundle + VERSION 0.0.1 + SOURCES + disc_mock_activator.c + disc_mock_service.c +) +target_include_directories(topology_manager_disc_mock_bundle PRIVATE + ${CPPUTEST_INCLUDE_DIR} + $<TARGET_PROPERTY:Celix::rsa_discovery_common,INCLUDE_DIRECTORIES> +) +target_link_libraries(topology_manager_disc_mock_bundle PRIVATE ${CPPUTEST_LIBRARY} Celix::framework) http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/topology_manager/tms_tst/disc_mock/disc_mock_activator.c ---------------------------------------------------------------------- diff --git a/bundles/remote_services/topology_manager/tms_tst/disc_mock/disc_mock_activator.c b/bundles/remote_services/topology_manager/tms_tst/disc_mock/disc_mock_activator.c new file mode 100644 index 0000000..d07ce02 --- /dev/null +++ b/bundles/remote_services/topology_manager/tms_tst/disc_mock/disc_mock_activator.c @@ -0,0 +1,149 @@ +/* + *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. + */ +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <service_tracker_customizer.h> +#include <service_tracker.h> + +#include "bundle_activator.h" +#include "bundle_context.h" +#include "service_registration.h" +#include "service_reference.h" +#include "celix_errno.h" + +#include "disc_mock_service.h" +#include "constants.h" +#include "remote_constants.h" + +celix_status_t discovery_endpointAdded(void *handle, endpoint_description_pt endpoint, char *matchedFilter); +celix_status_t discovery_endpointRemoved(void *handle, endpoint_description_pt endpoint, char *matchedFilter); + +celix_status_t bundleActivator_create(bundle_context_pt context, void **out) { + celix_status_t status = CELIX_SUCCESS; + struct disc_mock_activator *act = calloc(1, sizeof(*act)); + if (act != NULL) { + act->context = context; + discMockService_create(act, &act->serv); + act->endpointListener = NULL; + act->endpointListenerService = NULL; + status = arrayList_create(&act->endpointList); + } else { + status = CELIX_ENOMEM; + } + + if (status == CELIX_SUCCESS) { + *out = act; + } else if (act != NULL) { + free(act); + } + + return CELIX_SUCCESS; +} + +celix_status_t bundleActivator_start(void * userData, bundle_context_pt context) { + celix_status_t status; + struct disc_mock_activator * act = userData; + const char *uuid = NULL; + + act->reg = NULL; + status = bundleContext_registerService(context, DISC_MOCK_SERVICE_NAME, act->serv, NULL, &act->reg); + + bundleContext_getProperty(context, OSGI_FRAMEWORK_FRAMEWORK_UUID, &uuid); + + if (!uuid) { + return CELIX_ILLEGAL_STATE; + } + + size_t len = 11 + strlen(OSGI_FRAMEWORK_OBJECTCLASS) + strlen(OSGI_RSA_ENDPOINT_FRAMEWORK_UUID) + strlen(uuid); + char *scope = malloc(len + 1); + if (!scope) { + return CELIX_ENOMEM; + } + + sprintf(scope, "(&(%s=*)(%s=%s))", OSGI_FRAMEWORK_OBJECTCLASS, OSGI_RSA_ENDPOINT_FRAMEWORK_UUID, uuid); + scope[len] = 0; + + properties_pt props = properties_create(); + properties_set(props, "DISCOVERY", "true"); + properties_set(props, (char *) OSGI_ENDPOINT_LISTENER_SCOPE, scope); + + if (status == CELIX_SUCCESS) { + endpoint_listener_pt endpointListener = calloc(1, sizeof(struct endpoint_listener)); + + if (endpointListener) { + endpointListener->handle = act; + endpointListener->endpointAdded = discovery_endpointAdded; + endpointListener->endpointRemoved = discovery_endpointRemoved; + + status = bundleContext_registerService(context, (char *) OSGI_ENDPOINT_LISTENER_SERVICE, endpointListener, props, &act->endpointListenerService); + + if (status == CELIX_SUCCESS) { + act->endpointListener = endpointListener; + } else { + free(endpointListener); + } + } + } + // We can release the scope, as properties_set makes a copy of the key & value... + free(scope); + + return status; +} + +celix_status_t bundleActivator_stop(void * userData, bundle_context_pt context) { + celix_status_t status; + struct disc_mock_activator * act = userData; + + status = serviceRegistration_unregister(act->reg); + + return status; +} + +celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt context) { + struct disc_mock_activator *act = userData; + if (act != NULL) { + discMockService_destroy(act->serv); + + free(act->endpointListener); + arrayList_destroy(act->endpointList); + free(act); + } + return CELIX_SUCCESS; +} + +celix_status_t discovery_endpointAdded(void *handle, endpoint_description_pt endpoint, char *matchedFilter) { + celix_status_t status = CELIX_SUCCESS; + struct disc_mock_activator *act = handle; + + printf("%s\n", __func__); + arrayList_add(act->endpointList, endpoint); + + return status; +} + +celix_status_t discovery_endpointRemoved(void *handle, endpoint_description_pt endpoint, char *matchedFilter) { + celix_status_t status = CELIX_SUCCESS; + struct disc_mock_activator *act = handle; + printf("%s\n", __func__); + arrayList_removeElement(act->endpointList, endpoint); + + return status; +} + http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/topology_manager/tms_tst/disc_mock/disc_mock_service.c ---------------------------------------------------------------------- diff --git a/bundles/remote_services/topology_manager/tms_tst/disc_mock/disc_mock_service.c b/bundles/remote_services/topology_manager/tms_tst/disc_mock/disc_mock_service.c new file mode 100644 index 0000000..0bb89bb --- /dev/null +++ b/bundles/remote_services/topology_manager/tms_tst/disc_mock/disc_mock_service.c @@ -0,0 +1,61 @@ +/* + *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. + */ +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <service_tracker_customizer.h> +#include <service_tracker.h> + +#include "bundle_activator.h" +#include "bundle_context.h" +#include "service_registration.h" +#include "service_reference.h" +#include "celix_errno.h" + +#include "disc_mock_service.h" + + +celix_status_t test(void *handle, array_list_pt *descrList); + +celix_status_t discMockService_create(void *handle, disc_mock_service_pt *serv) +{ + *serv = calloc(1, sizeof(struct disc_mock_service)); + if (*serv == NULL) + return CELIX_ENOMEM; + + (*serv)->handle = handle; + (*serv)->getEPDescriptors = test; + + return CELIX_SUCCESS; +} + +celix_status_t discMockService_destroy(disc_mock_service_pt serv) +{ + free(serv); + + return CELIX_SUCCESS; +} + +celix_status_t test(void *handle, array_list_pt *descrList) +{ + struct disc_mock_activator *act = handle; + *descrList = act->endpointList; + + return CELIX_SUCCESS; +} http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/topology_manager/tms_tst/disc_mock/disc_mock_service.h ---------------------------------------------------------------------- diff --git a/bundles/remote_services/topology_manager/tms_tst/disc_mock/disc_mock_service.h b/bundles/remote_services/topology_manager/tms_tst/disc_mock/disc_mock_service.h new file mode 100644 index 0000000..9f0fd3c --- /dev/null +++ b/bundles/remote_services/topology_manager/tms_tst/disc_mock/disc_mock_service.h @@ -0,0 +1,56 @@ +/* + *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. + */ + +#ifndef DISC_MOCK_SERVICE_H +#define DISC_MOCK_SERVICE_H + +#include "bundle_context.h" +#include "endpoint_listener.h" +#include "service_registration.h" + +#define DISC_MOCK_SERVICE_NAME "disc_mock_service" + +struct disc_mock_service { + void *handle;// disc_mock_activator_pt + celix_status_t (*getEPDescriptors)(void *handle, array_list_pt *descrList); +}; + +typedef struct disc_mock_service *disc_mock_service_pt; + +struct disc_mock_activator { + bundle_context_pt context; + disc_mock_service_pt serv; + service_registration_pt reg; + +// service_tracker_customizer_pt cust; +// service_tracker_pt tracker; + endpoint_listener_pt endpointListener; + service_registration_pt endpointListenerService; + + array_list_pt endpointList; +}; + + + + + +celix_status_t discMockService_create(void *handle, disc_mock_service_pt *serv); +celix_status_t discMockService_destroy(disc_mock_service_pt serv); + +#endif //CELIX_TST_SERVICE_H http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/topology_manager/tms_tst/run_tests.cpp ---------------------------------------------------------------------- diff --git a/bundles/remote_services/topology_manager/tms_tst/run_tests.cpp b/bundles/remote_services/topology_manager/tms_tst/run_tests.cpp new file mode 100644 index 0000000..1ad1d9e --- /dev/null +++ b/bundles/remote_services/topology_manager/tms_tst/run_tests.cpp @@ -0,0 +1,24 @@ +/* + *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. + */ +#include <CppUTest/TestHarness.h> +#include "CppUTest/CommandLineTestRunner.h" + +int main(int argc, char** argv) { + return RUN_ALL_TESTS(argc, argv); +} http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/topology_manager/tms_tst/scope.json ---------------------------------------------------------------------- diff --git a/bundles/remote_services/topology_manager/tms_tst/scope.json b/bundles/remote_services/topology_manager/tms_tst/scope.json new file mode 100644 index 0000000..a4893e3 --- /dev/null +++ b/bundles/remote_services/topology_manager/tms_tst/scope.json @@ -0,0 +1,15 @@ +{ +"exportServices": [ +{ +"filter": "(objectClass=org.apache.celix.calc.*)", +"key2": "inaetics" +}, +{ +"filter": "(objectClass=org.inaetics.demonstrator.*)", +"key1": "value1", +"key2": "value2" +} +], +"importServices": [ +] +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/topology_manager/tms_tst/scope2.json ---------------------------------------------------------------------- diff --git a/bundles/remote_services/topology_manager/tms_tst/scope2.json b/bundles/remote_services/topology_manager/tms_tst/scope2.json new file mode 100644 index 0000000..4115c2f --- /dev/null +++ b/bundles/remote_services/topology_manager/tms_tst/scope2.json @@ -0,0 +1,22 @@ +{ +"exportServices": [ +{ +"filter": "(&(objectClass=org.apache.celix.calc.api.Calculator2)(module=Calc))", +"zone": "thales" +}, +{ +"filter": "(objectClass=org.apache.celix.calc.*)", +"key2": "inaetics" +}, +{ +"filter": "(objectClass=org.inaetics.demonstrator.*)", +"key1": "value1", +"key2": "value2" +} +], +"importServices": [ +{ +"filter": "(&(objectClass=org.apache.celix.test.*))" +} +] +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/topology_manager/tms_tst/scope3.json ---------------------------------------------------------------------- diff --git a/bundles/remote_services/topology_manager/tms_tst/scope3.json b/bundles/remote_services/topology_manager/tms_tst/scope3.json new file mode 100644 index 0000000..c7c0b29 --- /dev/null +++ b/bundles/remote_services/topology_manager/tms_tst/scope3.json @@ -0,0 +1,28 @@ +{ +"exportServices": [ +{ +"filter": "(&(objectClass=org.apache.celix.calc.api.Calculator2)(module=Calc))", +"zone": "thales", +"key1": "value1" +}, +{ +"filter": "(&(objectClass=org.apache.celix.calc.api.Calculator2)(module=Calc))", +"zone": "same_property_name_so_shall_give_Error" +}, +{ +"filter": "(objectClass=org.apache.celix.*)", +"key2": "inaetics" +}, +{ +"filter": "(objectClass=org.inaetics.demonstrator.*)", +"key1": "value1", +"key2": "value2" +} +], +"importServices": [ +{ +"filter": "(key3=value3)" +} +] +} + http://git-wip-us.apache.org/repos/asf/celix/blob/3bce889b/bundles/remote_services/topology_manager/tms_tst/scope4.json ---------------------------------------------------------------------- diff --git a/bundles/remote_services/topology_manager/tms_tst/scope4.json b/bundles/remote_services/topology_manager/tms_tst/scope4.json new file mode 100644 index 0000000..2eccb63 --- /dev/null +++ b/bundles/remote_services/topology_manager/tms_tst/scope4.json @@ -0,0 +1,21 @@ +{ +"exportServices": [ +{ +"filter": "(objectClass=org.apache.celix.calc.api.Calculator2)", +"zone": "thales" +}, +{ +"filter": "(objectClass=org.apache.celix.calc.*)", +"zone": "inaetics" +} +], +"importServices": [ +{ +"filter": "(key3=value3)" +}, +{ +"filter": "(zone=thales)" +} +] +} +