<commit_before>/**
 *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:<EMAIL>">Apache Celix Project Team</a>
 *  \copyright	Apache License, Version 2.0
 */
#include <stdio.h>
#include <stdlib.h>

#include "topology_manager.h"
#include "bundle_context.h"
#include "constants.h"
#include "module.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"

struct topology_manager {
	bundle_context_pt context;

	celix_thread_mutex_t rsaListLock;
	array_list_pt rsaList;

	celix_thread_mutex_t exportedServicesLock;
	hash_map_pt exportedServices;

	celix_thread_mutex_t importedServicesLock;
	hash_map_pt importedServices;

	celix_thread_mutex_t importInterestsLock;
	hash_map_pt importInterests;
};

struct import_interest {
	char *filter;
	int refs;
};

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, topology_manager_pt *manager) {
	celix_status_t status = CELIX_SUCCESS;

	*manager = malloc(sizeof(**manager));
	if (!*manager) {
		return CELIX_ENOMEM;
	}

	(*manager)->context = context;
	(*manager)->rsaList = NULL;
	arrayList_create(&(*manager)->rsaList);

	status = celixThreadMutex_create(&(*manager)->rsaListLock, NULL);
	status = celixThreadMutex_create(&(*manager)->exportedServicesLock, NULL);
	status = celixThreadMutex_create(&(*manager)->importedServicesLock, NULL);
	status = celixThreadMutex_create(&(*manager)->importInterestsLock, NULL);

	(*manager)->exportedServices = hashMap_create(serviceReference_hashCode, NULL, serviceReference_equals2, NULL);
	(*manager)->importedServices = hashMap_create(NULL, NULL, NULL, NULL);
	(*manager)->importInterests = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);

	return status;
}

celix_status_t topologyManager_destroy(topology_manager_pt manager) {
	celix_status_t status = CELIX_SUCCESS;

	status = celixThreadMutex_lock(&manager->rsaListLock);

	arrayList_destroy(manager->rsaList);

	status = celixThreadMutex_unlock(&manager->rsaListLock);
	status = celixThreadMutex_destroy(&manager->rsaListLock);

	status = celixThreadMutex_lock(&manager->exportedServicesLock);

	hashMap_destroy(manager->exportedServices, false, false);

	status = celixThreadMutex_unlock(&manager->exportedServicesLock);
	status = celixThreadMutex_destroy(&manager->exportedServicesLock);

	status = celixThreadMutex_lock(&manager->importedServicesLock);

	hashMap_destroy(manager->importedServices, false, false);

	status = celixThreadMutex_unlock(&manager->importedServicesLock);
	status = celixThreadMutex_destroy(&manager->importedServicesLock);

	status = celixThreadMutex_lock(&manager->importInterestsLock);

	hashMap_destroy(manager->importInterests, false, false);

	status = celixThreadMutex_unlock(&manager->importInterestsLock);
	status = celixThreadMutex_destroy(&manager->importInterestsLock);

	free(manager);

	return status;
}


celix_status_t topologyManager_rsaAdding(void * handle, service_reference_pt reference, void **service) {
	celix_status_t status = CELIX_SUCCESS;
	topology_manager_pt manager = 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 = CELIX_SUCCESS;
	topology_manager_pt manager = handle;
	remote_service_admin_service_pt rsa = (remote_service_admin_service_pt) service;
	fw_log(logger, OSGI_FRAMEWORK_LOG_INFO, "TOPOLOGY_MANAGER: Added RSA");

	status = celixThreadMutex_lock(&manager->rsaListLock);
	arrayList_add(manager->rsaList, rsa);
	status = celixThreadMutex_unlock(&manager->rsaListLock);

	// add already imported services to new rsa
	status = celixThreadMutex_lock(&manager->importedServicesLock);
	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);
		import_registration_pt import = NULL;

		status = rsa->importService(rsa->admin, endpoint, &import);

		if (status == CELIX_SUCCESS) {
		    hash_map_pt imports = hashMapEntry_getValue(entry);
			hashMap_put(imports, service, import);
		}
	}

	status = celixThreadMutex_unlock(&manager->importedServicesLock);

	// add already exported services to new rsa
	status = celixThreadMutex_lock(&manager->exportedServicesLock);
    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);
	    char *serviceId = NULL;

	    serviceReference_getProperty(reference, (char *)OSGI_FRAMEWORK_SERVICE_ID, &serviceId);

	    array_list_pt endpoints = NULL;
		status = rsa->exportService(rsa->admin, serviceId, NULL, &endpoints);

		if (status == CELIX_SUCCESS) {
			hash_map_pt exports = hashMapEntry_getValue(entry);
			hashMap_put(exports, rsa, endpoints);
			status = topologyManager_notifyListenersEndpointAdded(manager, rsa, endpoints);
		}
    }

	status = 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 = handle;

    fw_log(logger, OSGI_FRAMEWORK_LOG_INFO, "TOPOLOGY_MANAGER: Removed RSA");

    remote_service_admin_service_pt rsa = (remote_service_admin_service_pt) service;

    status = celixThreadMutex_lock(&manager->exportedServicesLock);

    hash_map_iterator_pt iter = hashMapIterator_create(manager->exportedServices);

    while (hashMapIterator_hasNext(iter)) {
        int exportsIter = 0;

        hash_map_pt exports = hashMapIterator_nextValue(iter);
        array_list_pt exports_list = hashMap_get(exports, rsa);

        if (exports_list != NULL) {
            for (exportsIter = 0; exportsIter < arrayList_size(exports_list); exportsIter++) {
                export_registration_pt export = arrayList_get(exports_list, exportsIter);
                rsa->exportRegistration_close(export);
                topologyManager_notifyListenersEndpointRemoved(manager, rsa, export);
            }

            arrayList_destroy(exports_list);
            exports_list = NULL;
        }

        hashMap_remove(exports, rsa);
        rsa = NULL;
    }
    status = celixThreadMutex_unlock(&manager->exportedServicesLock);

    fw_log(logger, OSGI_FRAMEWORK_LOG_INFO, "TOPOLOGY_MANAGER: Removed RSA");

    status = celixThreadMutex_lock(&manager->rsaListLock);
    arrayList_removeElement(manager->rsaList, rsa);
    status = celixThreadMutex_unlock(&manager->rsaListLock);

    return status;
}

celix_status_t topologyManager_getRSAs(topology_manager_pt manager, array_list_pt *rsaList) {
	celix_status_t status = CELIX_SUCCESS;

	status = arrayList_create(rsaList);
	if (status != CELIX_SUCCESS) {
		return CELIX_ENOMEM;
	}

	status = celixThreadMutex_lock(&manager->rsaListLock);
	arrayList_addAll(*rsaList, manager->rsaList);
	status = celixThreadMutex_unlock(&manager->rsaListLock);
<commit_msg>CELIX-177: removed wrong NULL assignment<commit_after>/**
 *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:<EMAIL>">Apache Celix Project Team</a>
 *  \copyright	Apache License, Version 2.0
 */
#include <stdio.h>
#include <stdlib.h>

#include "topology_manager.h"
#include "bundle_context.h"
#include "constants.h"
#include "module.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"

struct topology_manager {
	bundle_context_pt context;

	celix_thread_mutex_t rsaListLock;
	array_list_pt rsaList;

	celix_thread_mutex_t exportedServicesLock;
	hash_map_pt exportedServices;

	celix_thread_mutex_t importedServicesLock;
	hash_map_pt importedServices;

	celix_thread_mutex_t importInterestsLock;
	hash_map_pt importInterests;
};

struct import_interest {
	char *filter;
	int refs;
};

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, topology_manager_pt *manager) {
	celix_status_t status = CELIX_SUCCESS;

	*manager = malloc(sizeof(**manager));
	if (!*manager) {
		return CELIX_ENOMEM;
	}

	(*manager)->context = context;
	(*manager)->rsaList = NULL;
	arrayList_create(&(*manager)->rsaList);

	status = celixThreadMutex_create(&(*manager)->rsaListLock, NULL);
	status = celixThreadMutex_create(&(*manager)->exportedServicesLock, NULL);
	status = celixThreadMutex_create(&(*manager)->importedServicesLock, NULL);
	status = celixThreadMutex_create(&(*manager)->importInterestsLock, NULL);

	(*manager)->exportedServices = hashMap_create(serviceReference_hashCode, NULL, serviceReference_equals2, NULL);
	(*manager)->importedServices = hashMap_create(NULL, NULL, NULL, NULL);
	(*manager)->importInterests = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL);

	return status;
}

celix_status_t topologyManager_destroy(topology_manager_pt manager) {
	celix_status_t status = CELIX_SUCCESS;

	status = celixThreadMutex_lock(&manager->rsaListLock);

	arrayList_destroy(manager->rsaList);

	status = celixThreadMutex_unlock(&manager->rsaListLock);
	status = celixThreadMutex_destroy(&manager->rsaListLock);

	status = celixThreadMutex_lock(&manager->exportedServicesLock);

	hashMap_destroy(manager->exportedServices, false, false);

	status = celixThreadMutex_unlock(&manager->exportedServicesLock);
	status = celixThreadMutex_destroy(&manager->exportedServicesLock);

	status = celixThreadMutex_lock(&manager->importedServicesLock);

	hashMap_destroy(manager->importedServices, false, false);

	status = celixThreadMutex_unlock(&manager->importedServicesLock);
	status = celixThreadMutex_destroy(&manager->importedServicesLock);

	status = celixThreadMutex_lock(&manager->importInterestsLock);

	hashMap_destroy(manager->importInterests, false, false);

	status = celixThreadMutex_unlock(&manager->importInterestsLock);
	status = celixThreadMutex_destroy(&manager->importInterestsLock);

	free(manager);

	return status;
}


celix_status_t topologyManager_rsaAdding(void * handle, service_reference_pt reference, void **service) {
	celix_status_t status = CELIX_SUCCESS;
	topology_manager_pt manager = 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 = CELIX_SUCCESS;
	topology_manager_pt manager = handle;
	remote_service_admin_service_pt rsa = (remote_service_admin_service_pt) service;
	fw_log(logger, OSGI_FRAMEWORK_LOG_INFO, "TOPOLOGY_MANAGER: Added RSA");

	status = celixThreadMutex_lock(&manager->rsaListLock);
	arrayList_add(manager->rsaList, rsa);
	status = celixThreadMutex_unlock(&manager->rsaListLock);

	// add already imported services to new rsa
	status = celixThreadMutex_lock(&manager->importedServicesLock);
	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);
		import_registration_pt import = NULL;

		status = rsa->importService(rsa->admin, endpoint, &import);

		if (status == CELIX_SUCCESS) {
		    hash_map_pt imports = hashMapEntry_getValue(entry);
			hashMap_put(imports, service, import);
		}
	}

	status = celixThreadMutex_unlock(&manager->importedServicesLock);

	// add already exported services to new rsa
	status = celixThreadMutex_lock(&manager->exportedServicesLock);
    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);
	    char *serviceId = NULL;

	    serviceReference_getProperty(reference, (char *)OSGI_FRAMEWORK_SERVICE_ID, &serviceId);

	    array_list_pt endpoints = NULL;
		status = rsa->exportService(rsa->admin, serviceId, NULL, &endpoints);

		if (status == CELIX_SUCCESS) {
			hash_map_pt exports = hashMapEntry_getValue(entry);
			hashMap_put(exports, rsa, endpoints);
			status = topologyManager_notifyListenersEndpointAdded(manager, rsa, endpoints);
		}
    }

	status = 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 = handle;

    fw_log(logger, OSGI_FRAMEWORK_LOG_INFO, "TOPOLOGY_MANAGER: Removed RSA");

    remote_service_admin_service_pt rsa = (remote_service_admin_service_pt) service;

    status = celixThreadMutex_lock(&manager->exportedServicesLock);

    hash_map_iterator_pt iter = hashMapIterator_create(manager->exportedServices);

    while (hashMapIterator_hasNext(iter)) {
        int exportsIter = 0;

        hash_map_pt exports = hashMapIterator_nextValue(iter);
        array_list_pt exports_list = hashMap_get(exports, rsa);

        if (exports_list != NULL) {
            for (exportsIter = 0; exportsIter < arrayList_size(exports_list); exportsIter++) {
                export_registration_pt export = arrayList_get(exports_list, exportsIter);
                rsa->exportRegistration_close(export);
                topologyManager_notifyListenersEndpointRemoved(manager, rsa, export);
            }

            arrayList_destroy(exports_list);
            exports_list = NULL;
        }

        hashMap_remove(exports, rsa);
    }
    status = celixThreadMutex_unlock(&manager->exportedServicesLock);

    fw_log(logger, OSGI_FRAMEWORK_LOG_INFO, "TOPOLOGY_MANAGER: Removed RSA");

    status = celixThreadMutex_lock(&manager->rsaListLock);
    arrayList_removeElement(manager->rsaList, rsa);
    status = celixThreadMutex_unlock(&manager->rsaListLock);

    return status;
}

celix_status_t topologyManager_getRSAs(topology_manager_pt manager, array_list_pt *rsaList) {
	celix_status_t status = CELIX_SUCCESS;

	status = arrayList_create(rsaList);
	if (status != CELIX_SUCCESS) {
		return CELIX_ENOMEM;
	}

	status = celixThreadMutex_lock(&manager->rsaListLock);
	arrayList_addAll(*rsaList, manager->rsaList);
	status = celixThreadMutex_unlock(&manager->rsaListLock);

{'fraction_non_alphanumeric': 0.09253680441084522, 'fraction_numerical': 0.0018757460353549707, 'mean_word_length': 6.080080482897384, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 113, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '827837', 'n_tokens_mistral': 5547, 'n_tokens_neox': 5354, 'n_words': 1076}