blob: 6e40c58d8e4942dde87d75353a69005f6bf0dc07 [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 "celix_framework_bundle.h"
#include "celix_condition.h"
#include "celix_constants.h"
#include "celix_threads.h"
#include "celix_dependency_manager.h"
#include "framework_private.h"
#define CELIX_FRAMEWORK_CONDITION_SERVICES_ENABLED_DEFAULT true
/**
* @brief Celix framework bundle activator struct.
*/
typedef struct celix_framework_bundle {
celix_bundle_context_t* ctx;
celix_condition_t conditionInstance; /**< condition instance which can be used for multiple condition services.*/
framework_listener_t listener; /**< framework listener to check if the framework is ready. */
celix_thread_mutex_t mutex; /**< protects below. */
long trueConditionSvcId; /**< service id of the condition service which is always true. */
long frameworkReadyOrErrorConditionSvcId; /**< service id of the condition service which is set when the framework
is ready or started up with an error */
} celix_framework_bundle_t;
celix_status_t celix_frameworkBundle_create(celix_bundle_context_t* ctx, void** userData) {
*userData = NULL;
celix_framework_bundle_t* act = calloc(1, sizeof(*act));
if (!act) {
return ENOMEM;
}
celix_status_t status = celixThreadMutex_create(&act->mutex, NULL);
if (status != CELIX_SUCCESS) {
free(act);
return status;
}
act->ctx = ctx;
act->trueConditionSvcId = -1L;
act->listener.handle = act;
act->listener.frameworkEvent = celix_frameworkBundle_handleFrameworkEvent;
act->frameworkReadyOrErrorConditionSvcId = -1L;
act->conditionInstance.handle = act;
*userData = act;
return CELIX_SUCCESS;
}
static void celix_frameworkBundle_registerTrueCondition(celix_framework_bundle_t* act) {
celix_service_registration_options_t opts = CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS;
opts.serviceName = CELIX_CONDITION_SERVICE_NAME;
opts.serviceVersion = CELIX_CONDITION_SERVICE_VERSION;
opts.svc = &act->conditionInstance;
opts.properties = celix_properties_create();
if (opts.properties) {
celix_properties_set(opts.properties, CELIX_CONDITION_ID, CELIX_CONDITION_ID_TRUE);
act->trueConditionSvcId = celix_bundleContext_registerServiceWithOptionsAsync(act->ctx, &opts);
} else {
celix_bundleContext_log(act->ctx, CELIX_LOG_LEVEL_ERROR, "Cannot create properties for true condition service");
}
}
celix_status_t celix_frameworkBundle_handleFrameworkEvent(void* handle, framework_event_t* event) {
framework_listener_t* listener = handle;
celix_framework_bundle_t* act = listener->handle;
if (event->type == OSGI_FRAMEWORK_EVENT_STARTED || event->type == OSGI_FRAMEWORK_EVENT_ERROR) {
celixThreadMutex_lock(&act->mutex);
celix_service_registration_options_t opts = CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS;
opts.serviceName = CELIX_CONDITION_SERVICE_NAME;
opts.serviceVersion = CELIX_CONDITION_SERVICE_VERSION;
opts.svc = &act->conditionInstance;
opts.properties = celix_properties_create();
if (opts.properties) {
if (event->type == OSGI_FRAMEWORK_EVENT_STARTED) {
celix_properties_set(opts.properties, CELIX_CONDITION_ID, CELIX_CONDITION_ID_FRAMEWORK_READY);
celix_bundleContext_log(
act->ctx,
CELIX_LOG_LEVEL_DEBUG,
"Framework started event received -> registering framework.ready condition service");
} else /*error*/ {
celix_properties_set(opts.properties, CELIX_CONDITION_ID, CELIX_CONDITION_ID_FRAMEWORK_ERROR);
celix_bundleContext_log(
act->ctx,
CELIX_LOG_LEVEL_INFO,
"Framework error event received -> registering framework.error condition service");
}
act->frameworkReadyOrErrorConditionSvcId =
celix_bundleContext_registerServiceWithOptionsAsync(act->ctx, &opts);
} else {
celix_bundleContext_log(act->ctx,
CELIX_LOG_LEVEL_ERROR,
"Cannot create properties for framework.ready/framework.error condition service");
}
celixThreadMutex_unlock(&act->mutex);
}
return CELIX_SUCCESS;
}
celix_status_t celix_frameworkBundle_start(void* userData, celix_bundle_context_t* ctx) {
celix_framework_bundle_t* act = userData;
celix_framework_t* fw = celix_bundleContext_getFramework(ctx);
celix_bundle_t* bnd = celix_bundleContext_getBundle(ctx);
bool conditionsEnabled = celix_bundleContext_getPropertyAsBool(
ctx, CELIX_FRAMEWORK_CONDITION_SERVICES_ENABLED, CELIX_FRAMEWORK_CONDITION_SERVICES_ENABLED_DEFAULT);
if (!conditionsEnabled) {
return CELIX_SUCCESS;
}
celix_status_t status = fw_addFrameworkListener(fw, bnd, &act->listener);
if (status != CELIX_SUCCESS) {
celix_bundleContext_log(
ctx, CELIX_LOG_LEVEL_ERROR, "Cannot add framework listener for framework bundle");
return status;
}
celix_frameworkBundle_registerTrueCondition(act);
if (act->trueConditionSvcId < 0) {
fw_removeFrameworkListener(fw, bnd, &act->listener);
return CELIX_BUNDLE_EXCEPTION;
}
return CELIX_SUCCESS;
}
celix_status_t celix_frameworkBundle_stop(void* userData, celix_bundle_context_t* ctx) {
celix_framework_bundle_t* act = userData;
celix_framework_t* framework = celix_bundleContext_getFramework(ctx);
// remove framework listener
fw_removeFrameworkListener(framework, celix_bundleContext_getBundle(ctx), &act->listener);
// remove framework true condition service and - if present - framework.ready condition service,
celixThreadMutex_lock(&act->mutex);
long trueConditionSvcId = act->trueConditionSvcId;
long frameworkReadyOrErrorConditionSvcId = act->frameworkReadyOrErrorConditionSvcId;
act->trueConditionSvcId = -1L;
act->frameworkReadyOrErrorConditionSvcId = -1L;
celixThreadMutex_unlock(&act->mutex);
celix_bundleContext_unregisterService(ctx, frameworkReadyOrErrorConditionSvcId);
celix_bundleContext_unregisterService(ctx, trueConditionSvcId);
// framework shutdown
celix_framework_shutdownAsync(framework);
return CELIX_SUCCESS;
}
celix_status_t celix_frameworkBundle_destroy(void* userData, celix_bundle_context_t* ctx __attribute__((unused))) {
celix_framework_bundle_t* act = userData;
if (act) {
celixThreadMutex_destroy(&act->mutex);
free(userData);
}
return CELIX_SUCCESS;
}