blob: 21a77d450485deb61bee8f9ea382d564b4cedcb6 [file] [log] [blame]
/*
* 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 <pthread.h>
#include <stdlib.h>
#include <dm_dependency_manager.h>
#include <memory.h>
#include <celix_utils.h>
#include "bundle_context.h"
#include "dm_component_impl.h"
#include "dm_dependency_manager_impl.h"
#include "celix_dependency_manager.h"
#include "celix_bundle.h"
#include "celix_framework.h"
celix_dependency_manager_t* celix_private_dependencyManager_create(celix_bundle_context_t *context) {
celix_dependency_manager_t *manager = calloc(1, sizeof(*manager));
if (manager != NULL) {
manager->ctx = context;
manager->components = celix_arrayList_create();
pthread_mutex_init(&manager->mutex, NULL);
}
return manager;
}
void celix_private_dependencyManager_destroy(celix_dependency_manager_t *manager) {
if (manager != NULL) {
celixThreadMutex_lock(&manager->mutex);
celix_arrayList_destroy(manager->components);
celixThreadMutex_unlock(&manager->mutex);
pthread_mutex_destroy(&manager->mutex);
free(manager);
}
}
celix_status_t celix_dependencyManager_add(celix_dependency_manager_t *manager, celix_dm_component_t *component) {
celix_status_t status = celix_dependencyManager_addAsync(manager, component);
celix_dependencyManager_wait(manager);
return status;
}
celix_status_t celix_dependencyManager_addAsync(celix_dependency_manager_t *manager, celix_dm_component_t *component) {
celixThreadMutex_lock(&manager->mutex);
celix_arrayList_add(manager->components, component);
celixThreadMutex_unlock(&manager->mutex);
return celix_private_dmComponent_enable(component);
}
static celix_status_t celix_dependencyManager_removeWithoutDestroy(celix_dependency_manager_t *manager, celix_dm_component_t *component) {
celix_status_t status = CELIX_SUCCESS;
celixThreadMutex_lock(&manager->mutex);
bool found = false;
for (int i = 0; i < celix_arrayList_size(manager->components); ++i) {
celix_dm_component_t* visit = celix_arrayList_get(manager->components, i);
if (visit == component) {
celix_arrayList_removeAt(manager->components, i);
found = true;
break;
}
}
celixThreadMutex_unlock(&manager->mutex);
if (!found) {
celix_bundleContext_log(
manager->ctx,
CELIX_LOG_LEVEL_ERROR,
"Cannot find component with ptr %p",
component);
status = CELIX_BUNDLE_EXCEPTION;
}
return status;
}
celix_status_t celix_dependencyManager_remove(celix_dependency_manager_t *manager, celix_dm_component_t *component) {
celix_status_t status = celix_dependencyManager_removeAsync(manager, component, NULL, NULL);
celix_dependencyManager_wait(manager);
return status;
}
celix_status_t celix_dependencyManager_removeAsync(
celix_dependency_manager_t *manager,
celix_dm_component_t *component,
void* doneData,
void (*doneCallback)(void* data)) {
celix_status_t status = celix_dependencyManager_removeWithoutDestroy(manager, component);
if (status == CELIX_SUCCESS) {
celix_dmComponent_destroyAsync(component, doneData, doneCallback);
}
return status;
}
celix_status_t celix_dependencyManager_removeAllComponents(celix_dependency_manager_t *manager) {
celix_status_t status = celix_dependencyManager_removeAllComponentsAsync(manager, NULL, NULL);
celix_dependencyManager_wait(manager);
return status;
}
struct celix_dependency_manager_removeall_data {
size_t destroysInProgress;
void *doneData;
void (*doneCallback)(void* data);
};
static void celix_dependencyManager_removeAllComponentsAsyncCallback(void *data) {
struct celix_dependency_manager_removeall_data* callbackData = data;
callbackData->destroysInProgress -= 1;
if (callbackData->destroysInProgress == 0) {
callbackData->doneCallback(callbackData->doneData);
free(callbackData);
}
}
celix_status_t celix_dependencyManager_removeAllComponentsAsync(celix_dependency_manager_t *manager, void *doneData, void (*doneCallback)(void *data)) {
celix_status_t status = CELIX_SUCCESS;
//setup callback data struct to synchronize when all components are destroyed (if doneCallback is not NULL)
struct celix_dependency_manager_removeall_data* callbackData = NULL;
if (doneCallback != NULL) {
callbackData = malloc(sizeof(*callbackData));
callbackData->destroysInProgress = 0;
callbackData->doneData = doneData;
callbackData->doneCallback = doneCallback;
}
//remove components and queue a async component destroy
celixThreadMutex_lock(&manager->mutex);
if (doneCallback != NULL) {
callbackData->destroysInProgress = celix_arrayList_size(manager->components);
}
if (celix_arrayList_size(manager->components) == 0 && doneCallback != NULL) {
//corner case: if no components are available, call done callback on event thread.
celix_framework_t* fw = celix_bundleContext_getFramework(manager->ctx);
long bndId = celix_bundleContext_getBundleId(manager->ctx);
celix_framework_fireGenericEvent(
fw,
-1,
bndId,
"celix_dependencyManager_removeAllComponentsAsync callback",
doneData,
doneCallback,
NULL,
NULL
);
free(callbackData);
}
for (int i = 0; i < celix_arrayList_size(manager->components); ++i) {
celix_dm_component_t *cmp = celix_arrayList_get(manager->components, i);
if (doneCallback != NULL) {
celix_dmComponent_destroyAsync(cmp, callbackData, celix_dependencyManager_removeAllComponentsAsyncCallback);
} else {
celix_dmComponent_destroyAsync(cmp, NULL, NULL);
}
}
celix_arrayList_clear(manager->components);
celixThreadMutex_unlock(&manager->mutex);
return status;
}
static void celix_dm_getInfoCallback(void *handle, const celix_bundle_t *bnd) {
celix_dependency_manager_info_t **out = handle;
if (celix_bundle_getState(bnd) != CELIX_BUNDLE_STATE_ACTIVE) {
return;
}
celix_bundle_context_t *context = NULL;
bundle_getContext((celix_bundle_t*)bnd, &context);
celix_dependency_manager_t *mng = celix_bundleContext_getDependencyManager(context);
celix_dependency_manager_info_t *info = calloc(1, sizeof(*info));
if (info != NULL) {
info->bndId = celix_bundle_getId(bnd);
info->bndSymbolicName = celix_utils_strdup(celix_bundle_getSymbolicName(bnd));
celixThreadMutex_lock(&mng->mutex);
celix_array_list_create_options_t opts = CELIX_EMPTY_ARRAY_LIST_CREATE_OPTIONS;
opts.simpleRemovedCallback = (void*)component_destroyComponentInfo;
info->components = celix_arrayList_createWithOptions(&opts);
int size = celix_arrayList_size(mng->components);
for (int i = 0; i < size; i += 1) {
celix_dm_component_t *cmp = celix_arrayList_get(mng->components, i);
celix_dm_component_info_t *cmpInfo = NULL;
component_getComponentInfo(cmp, &cmpInfo);
celix_arrayList_add(info->components, cmpInfo);
}
celixThreadMutex_unlock(&mng->mutex);
}
*out = info;
}
celix_dependency_manager_info_t* celix_dependencyManager_createInfo(celix_dependency_manager_t *manager, long bndId) {
celix_dependency_manager_info_t *info = NULL;
celix_bundleContext_useBundle(manager->ctx, bndId, &info, celix_dm_getInfoCallback);
return info;
}
static void celix_dm_getInfosCallback(void* handle, const celix_bundle_t* bnd) {
celix_array_list_t* infos = handle;
if (celix_bundle_getState(bnd) != CELIX_BUNDLE_STATE_ACTIVE) {
return;
}
celix_bundle_context_t* context = NULL;
bundle_getContext((celix_bundle_t*)bnd, &context);
celix_dependency_manager_t* mng = celix_bundleContext_getDependencyManager(context);
celix_dependency_manager_info_t* info = calloc(1, sizeof(*info));
info->bndId = celix_bundle_getId(bnd);
info->bndSymbolicName = celix_utils_strdup(celix_bundle_getSymbolicName(bnd));
celix_array_list_create_options_t opts = CELIX_EMPTY_ARRAY_LIST_CREATE_OPTIONS;
opts.simpleRemovedCallback = (void*)component_destroyComponentInfo;
info->components = celix_arrayList_createWithOptions(&opts);
celixThreadMutex_lock(&mng->mutex);
int size = celix_arrayList_size(mng->components);
for (int i = 0; i < size; i += 1) {
celix_dm_component_t* cmp = celix_arrayList_get(mng->components, i);
celix_dm_component_info_t* cmpInfo = NULL;
celix_dmComponent_getComponentInfo(cmp, &cmpInfo);
celix_arrayList_add(info->components, cmpInfo);
}
celix_arrayList_add(infos, info);
celixThreadMutex_unlock(&mng->mutex);
}
static void celix_dependencyManager_destroyInfoCallback(void *data, celix_array_list_entry_t entry) {
celix_dependency_manager_t* manager = data;
celix_dependency_manager_info_t* info = entry.voidPtrVal;
celix_dependencyManager_destroyInfo(manager, info);
}
celix_array_list_t * celix_dependencyManager_createInfos(celix_dependency_manager_t* manager) {
celix_array_list_create_options_t opts = CELIX_EMPTY_ARRAY_LIST_CREATE_OPTIONS;
opts.removedCallbackData = manager;
opts.removedCallback = celix_dependencyManager_destroyInfoCallback;
celix_array_list_t* infos = celix_arrayList_createWithOptions(&opts);
celix_framework_t* fw = celix_bundleContext_getFramework(manager->ctx);
celix_framework_useBundles(fw, true, infos, celix_dm_getInfosCallback);
return infos;
}
static void celix_dm_allComponentsActiveCallback(void *handle, const celix_bundle_t *bnd) {
bool *allActivePtr = handle;
if (celix_bundle_getState(bnd) != CELIX_BUNDLE_STATE_ACTIVE) {
return;
}
celix_bundle_context_t *context = NULL;
bundle_getContext((celix_bundle_t*)bnd, &context);
celix_dependency_manager_t *mng = celix_bundleContext_getDependencyManager(context);
bool allActive = celix_dependencyManager_areComponentsActive(mng);
if (!allActive) {
*allActivePtr = false;
}
}
bool celix_dependencyManager_allComponentsActive(celix_dependency_manager_t *manager) {
bool allActive = true;
celix_bundleContext_useBundles(manager->ctx, &allActive, celix_dm_allComponentsActiveCallback);
return allActive;
}
size_t celix_dependencyManager_nrOfComponents(celix_dependency_manager_t *mng) {
celixThreadMutex_lock(&mng->mutex);
size_t nr = (size_t)celix_arrayList_size(mng->components);
celixThreadMutex_unlock(&mng->mutex);
return nr;
}
void celix_dependencyManager_wait(celix_dependency_manager_t *mng) {
celix_framework_t *fw = celix_bundleContext_getFramework(mng->ctx);
if (!celix_framework_isCurrentThreadTheEventLoop(fw)) {
celix_bundleContext_waitForEvents(mng->ctx);
} else {
celix_bundleContext_log(mng->ctx, CELIX_LOG_LEVEL_WARNING,
"celix_dependencyManager_wait: Cannot wait for Celix event queue on the Celix event queue thread! "
"Use async dep man API instead.");
}
}
bool celix_dependencyManager_areComponentsActive(celix_dependency_manager_t *mng) {
bool allActive = true;
celixThreadMutex_lock(&mng->mutex);
int size = celix_arrayList_size(mng->components);
for (int i = 0; i < size; i += 1) {
celix_dm_component_t *cmp = celix_arrayList_get(mng->components, i);
if (!celix_dmComponent_isActive(cmp)) {
allActive = false;
break;
}
}
celixThreadMutex_unlock(&mng->mutex);
return allActive;
}
void celix_dependencyManager_destroyInfo(celix_dependency_manager_t *manager __attribute__((unused)), celix_dependency_manager_info_t *info) {
if (info != NULL) {
celix_arrayList_destroy(info->components);
free(info->bndSymbolicName);
free(info);
}
}
void celix_dependencyManager_destroyInfos(celix_dependency_manager_t *manager __attribute__((unused)), celix_array_list_t * infos /*entries celix_dm_dependency_manager_info_t*/) {
celix_arrayList_destroy(infos);
}
/************************ DEPRECATED API ************************************************/
celix_status_t dependencyManager_create(bundle_context_pt context, celix_dependency_manager_t **out) {
celix_status_t status = CELIX_SUCCESS;
celix_dependency_manager_t *manager = celix_bundleContext_getDependencyManager(context);
if (manager != NULL) {
*out = manager;
} else {
status = CELIX_BUNDLE_EXCEPTION;
}
return status;
}
void dependencyManager_destroy(celix_dependency_manager_t *manager) {
}
celix_status_t dependencyManager_add(celix_dependency_manager_t *manager, celix_dm_component_t *component) {
return celix_dependencyManager_add(manager, component);
}
celix_status_t dependencyManager_remove(celix_dependency_manager_t *manager, celix_dm_component_t *component) {
return celix_dependencyManager_remove(manager, component);
}
celix_status_t dependencyManager_removeAllComponents(celix_dependency_manager_t *manager) {
return celix_dependencyManager_removeAllComponents(manager);
}
celix_status_t dependencyManager_getInfo(celix_dependency_manager_t *manager, dm_dependency_manager_info_pt *out) {
celix_status_t status = CELIX_SUCCESS;
unsigned int i;
int size;
dm_component_info_pt cmpInfo = NULL;
dm_dependency_manager_info_pt info = calloc(1, sizeof(*info));
celixThreadMutex_lock(&manager->mutex);
if (info != NULL) {
arrayList_create(&info->components);
size = arrayList_size(manager->components);
for (i = 0; i < size; i += 1) {
celix_dm_component_t *cmp = arrayList_get(manager->components, i);
cmpInfo = NULL;
component_getComponentInfo(cmp, &cmpInfo);
arrayList_add(info->components, cmpInfo);
}
} else {
status = CELIX_ENOMEM;
}
celixThreadMutex_unlock(&manager->mutex);
if (status == CELIX_SUCCESS) {
*out = info;
}
return status;
}
void dependencyManager_destroyInfo(celix_dependency_manager_t *manager, celix_dependency_manager_info_t *info) {
celix_dependencyManager_destroyInfo(manager, info);
}
static void celix_dependencyManager_printInfoForEntry(bool fullInfo, bool useAnsiColors, FILE* stream, celix_dependency_manager_info_t* mngInfo) {
for (int i = 0; i < celix_arrayList_size(mngInfo->components); ++i) {
celix_dm_component_info_t *cmpInfo = celix_arrayList_get(mngInfo->components, i);
celix_dmComponent_printComponentInfo(cmpInfo, fullInfo, useAnsiColors, stream);
}
}
void celix_dependencyManager_printInfo(celix_dependency_manager_t* manager, bool fullInfo, bool useAnsiColors, FILE* stream) {
celix_array_list_t *infos = celix_dependencyManager_createInfos(manager);
for (int i = 0; i< celix_arrayList_size(infos); ++i) {
celix_dependency_manager_info_t* mngInfo = celix_arrayList_get(infos, i);
celix_dependencyManager_printInfoForEntry(fullInfo, useAnsiColors, stream, mngInfo);
}
celix_dependencyManager_destroyInfos(manager, infos);
}
void celix_dependencyManager_printInfoForBundle(celix_dependency_manager_t* manager, bool fullInfo, bool useAnsiColors, long bundleId, FILE* stream) {
celix_dependency_manager_info_t* mngInfo = celix_dependencyManager_createInfo(manager, bundleId);
if (mngInfo != NULL) {
celix_dependencyManager_printInfoForEntry(fullInfo, useAnsiColors, stream, mngInfo);
celix_dependencyManager_destroyInfo(manager, mngInfo);
}
}