| /* |
| * 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 <stdio.h> |
| #include <string.h> |
| #include <utils.h> |
| #include <assert.h> |
| #include <unistd.h> |
| |
| #include "celix_utils.h" |
| #include "celix_constants.h" |
| #include "bundle_context_private.h" |
| #include "framework_private.h" |
| #include "bundle.h" |
| #include "celix_bundle.h" |
| #include "celix_log.h" |
| #include "service_tracker.h" |
| #include "celix_dependency_manager.h" |
| #include "dm_dependency_manager_impl.h" |
| #include "celix_array_list.h" |
| #include "module.h" |
| #include "service_tracker_private.h" |
| #include "celix_array_list.h" |
| |
| static celix_status_t bundleContext_bundleChanged(void *handle, bundle_event_t *event); |
| static void bundleContext_cleanupBundleTrackers(bundle_context_t *ct); |
| static void bundleContext_cleanupServiceTrackers(bundle_context_t *ctx); |
| static void bundleContext_cleanupServiceTrackerTrackers(bundle_context_t *ctx); |
| static void bundleContext_cleanupServiceRegistration(bundle_context_t* ctx); |
| static long celix_bundleContext_trackServicesWithOptionsInternal(celix_bundle_context_t *ctx, const celix_service_tracking_options_t *opts, bool async); |
| |
| celix_status_t bundleContext_create(framework_pt framework, celix_framework_logger_t* logger, bundle_pt bundle, bundle_context_pt *bundle_context) { |
| celix_status_t status = CELIX_SUCCESS; |
| bundle_context_pt context = NULL; |
| |
| if (*bundle_context != NULL && framework == NULL && bundle == NULL) { |
| status = CELIX_ILLEGAL_ARGUMENT; |
| } else { |
| context = malloc(sizeof(*context)); |
| if (!context) { |
| status = CELIX_ENOMEM; |
| } else { |
| context->framework = framework; |
| context->bundle = bundle; |
| context->mng = NULL; |
| |
| celixThreadMutex_create(&context->mutex, NULL); |
| |
| arrayList_create(&context->svcRegistrations); |
| context->bundleTrackers = hashMap_create(NULL,NULL,NULL,NULL); |
| context->serviceTrackers = hashMap_create(NULL,NULL,NULL,NULL); |
| context->metaTrackers = hashMap_create(NULL,NULL,NULL,NULL); |
| context->stoppingTrackerEventIds = hashMap_create(NULL,NULL,NULL,NULL); |
| context->nextTrackerId = 1L; |
| |
| *bundle_context = context; |
| |
| } |
| } |
| |
| framework_logIfError(context->framework->logger, status, NULL, "Failed to create context"); |
| |
| return status; |
| } |
| |
| celix_status_t bundleContext_destroy(bundle_context_pt context) { |
| celix_status_t status = CELIX_SUCCESS; |
| |
| if (context != NULL) { |
| assert(hashMap_size(context->bundleTrackers) == 0); |
| hashMap_destroy(context->bundleTrackers, false, false); |
| assert(hashMap_size(context->serviceTrackers) == 0); |
| hashMap_destroy(context->serviceTrackers, false, false); |
| assert(hashMap_size(context->metaTrackers) == 0); |
| hashMap_destroy(context->metaTrackers, false, false); |
| assert(celix_arrayList_size(context->svcRegistrations) == 0); |
| celix_arrayList_destroy(context->svcRegistrations); |
| hashMap_destroy(context->stoppingTrackerEventIds, false, false); |
| |
| celixThreadMutex_destroy(&context->mutex); |
| |
| if (context->mng != NULL) { |
| celix_dependencyManager_removeAllComponents(context->mng); |
| celix_private_dependencyManager_destroy(context->mng); |
| context->mng = NULL; |
| } |
| |
| free(context); |
| } else { |
| status = CELIX_ILLEGAL_ARGUMENT; |
| } |
| |
| framework_logIfError(context->framework->logger, status, NULL, "Failed to destroy context"); |
| |
| return status; |
| } |
| |
| void celix_bundleContext_cleanup(celix_bundle_context_t *ctx) { |
| //NOTE not perfect, because stopping of registrations/tracker when the activator is destroyed can lead to segfault. |
| //but at least we can try to warn the bundle implementer that some cleanup is missing. |
| bundleContext_cleanupBundleTrackers(ctx); |
| bundleContext_cleanupServiceTrackers(ctx); |
| bundleContext_cleanupServiceTrackerTrackers(ctx); |
| bundleContext_cleanupServiceRegistration(ctx); |
| } |
| |
| celix_status_t bundleContext_getBundle(bundle_context_pt context, bundle_pt *out) { |
| celix_status_t status = CELIX_SUCCESS; |
| celix_bundle_t *bnd = celix_bundleContext_getBundle(context); |
| if (context == NULL) { |
| status = CELIX_ILLEGAL_ARGUMENT; |
| } |
| if (out != NULL) { |
| *out = bnd; |
| } |
| |
| framework_logIfError(context->framework->logger, status, NULL, "Failed to get bundle"); |
| |
| return status; |
| } |
| |
| celix_status_t bundleContext_getFramework(bundle_context_pt context, framework_pt *framework) { |
| celix_status_t status = CELIX_SUCCESS; |
| |
| if (context == NULL) { |
| status = CELIX_ILLEGAL_ARGUMENT; |
| } else { |
| *framework = context->framework; |
| } |
| |
| framework_logIfError(context->framework->logger, status, NULL, "Failed to get framework"); |
| |
| return status; |
| } |
| |
| celix_status_t bundleContext_installBundle(bundle_context_pt context, const char * location, bundle_pt *bundle) { |
| return bundleContext_installBundle2(context, location, NULL, bundle); |
| } |
| |
| celix_status_t bundleContext_installBundle2(bundle_context_pt context, const char *location, const char *inputFile, bundle_pt *bundle) { |
| celix_status_t status = CELIX_SUCCESS; |
| bundle_pt b = NULL; |
| |
| if (context != NULL) { |
| if (fw_installBundle(context->framework, &b, location, inputFile) != CELIX_SUCCESS) { |
| status = CELIX_FRAMEWORK_EXCEPTION; |
| } else { |
| *bundle = b; |
| } |
| } else { |
| status = CELIX_ILLEGAL_ARGUMENT; |
| } |
| |
| framework_logIfError(context->framework->logger, status, NULL, "Failed to install bundle"); |
| |
| return status; |
| } |
| |
| celix_status_t bundleContext_registerService(bundle_context_pt context, const char * serviceName, const void * svcObj, |
| properties_pt properties, service_registration_pt *service_registration) { |
| service_registration_pt registration = NULL; |
| celix_status_t status = CELIX_SUCCESS; |
| |
| if (context != NULL) { |
| long bndId = celix_bundle_getId(context->bundle); |
| fw_registerService(context->framework, ®istration, bndId, serviceName, svcObj, properties); |
| *service_registration = registration; |
| } else { |
| status = CELIX_ILLEGAL_ARGUMENT; |
| } |
| |
| framework_logIfError(context->framework->logger, status, NULL, "Failed to register service. serviceName '%s'", serviceName); |
| |
| return status; |
| } |
| |
| celix_status_t bundleContext_registerServiceFactory(bundle_context_pt context, const char * serviceName, service_factory_pt factory, |
| properties_pt properties, service_registration_pt *service_registration) { |
| service_registration_pt registration = NULL; |
| celix_status_t status = CELIX_SUCCESS; |
| |
| if (context != NULL && *service_registration == NULL) { |
| long bndId = celix_bundle_getId(context->bundle); |
| fw_registerServiceFactory(context->framework, ®istration, bndId, serviceName, factory, properties); |
| *service_registration = registration; |
| } else { |
| status = CELIX_ILLEGAL_ARGUMENT; |
| } |
| |
| framework_logIfError(context->framework->logger, status, NULL, "Failed to register service factory"); |
| |
| return status; |
| } |
| |
| celix_status_t bundleContext_getServiceReferences(bundle_context_pt context, const char * serviceName, const char * filter, array_list_pt *service_references) { |
| celix_status_t status = CELIX_SUCCESS; |
| |
| if (context != NULL && *service_references == NULL) { |
| fw_getServiceReferences(context->framework, service_references, context->bundle, serviceName, filter); |
| } else { |
| status = CELIX_ILLEGAL_ARGUMENT; |
| } |
| |
| framework_logIfError(context->framework->logger, status, NULL, "Failed to get service references"); |
| |
| return status; |
| } |
| |
| celix_status_t bundleContext_getServiceReference(bundle_context_pt context, const char * serviceName, service_reference_pt *service_reference) { |
| service_reference_pt reference = NULL; |
| array_list_pt services = NULL; |
| celix_status_t status = CELIX_SUCCESS; |
| |
| if (serviceName != NULL) { |
| if (bundleContext_getServiceReferences(context, serviceName, NULL, &services) == CELIX_SUCCESS) { |
| reference = (arrayList_size(services) > 0) ? arrayList_get(services, 0) : NULL; |
| arrayList_destroy(services); |
| *service_reference = reference; |
| } else { |
| status = CELIX_ILLEGAL_ARGUMENT; |
| } |
| } else { |
| status = CELIX_ILLEGAL_ARGUMENT; |
| } |
| |
| framework_logIfError(context->framework->logger, status, NULL, "Failed to get service reference"); |
| |
| return status; |
| } |
| |
| FRAMEWORK_EXPORT celix_status_t bundleContext_retainServiceReference(bundle_context_pt context, service_reference_pt ref) { |
| celix_status_t status = CELIX_SUCCESS; |
| |
| if (context != NULL && ref != NULL) { |
| serviceRegistry_retainServiceReference(context->framework->registry, context->bundle, ref); |
| } else { |
| status = CELIX_ILLEGAL_ARGUMENT; |
| } |
| |
| framework_logIfError(context->framework->logger, status, NULL, "Failed to get service references"); |
| |
| return status; |
| } |
| |
| celix_status_t bundleContext_ungetServiceReference(bundle_context_pt context, service_reference_pt reference) { |
| celix_status_t status = CELIX_SUCCESS; |
| |
| if (context != NULL && reference != NULL) { |
| status = framework_ungetServiceReference(context->framework, context->bundle, reference); |
| } else { |
| status = CELIX_ILLEGAL_ARGUMENT; |
| } |
| |
| framework_logIfError(context->framework->logger, status, NULL, "Failed to unget service_reference"); |
| |
| return status; |
| } |
| |
| celix_status_t bundleContext_getService(bundle_context_pt context, service_reference_pt reference, void** service_instance) { |
| celix_status_t status = CELIX_SUCCESS; |
| |
| if (context != NULL && reference != NULL && service_instance != NULL) { |
| /*NOTE argument service_instance should be considered a 'const void**'. |
| To ensure backwards compatibility a cast is made instead. |
| */ |
| status = fw_getService(context->framework, context->bundle, reference, (const void**) service_instance); |
| } else { |
| status = CELIX_ILLEGAL_ARGUMENT; |
| } |
| |
| if (status != CELIX_SUCCESS) { |
| fw_log(context->framework->logger, CELIX_LOG_LEVEL_ERROR, "Failed to get service"); |
| } |
| |
| return status; |
| } |
| |
| celix_status_t bundleContext_ungetService(bundle_context_pt context, service_reference_pt reference, bool *result) { |
| celix_status_t status = CELIX_SUCCESS; |
| |
| if (context != NULL && reference != NULL) { |
| status = framework_ungetService(context->framework, context->bundle, reference, result); |
| } else { |
| status = CELIX_ILLEGAL_ARGUMENT; |
| } |
| |
| framework_logIfError(context->framework->logger, status, NULL, "Failed to unget service"); |
| |
| return status; |
| } |
| |
| celix_status_t bundleContext_getBundles(bundle_context_pt context, array_list_pt *bundles) { |
| celix_status_t status = CELIX_SUCCESS; |
| |
| if (context == NULL || *bundles != NULL) { |
| status = CELIX_ILLEGAL_ARGUMENT; |
| } else { |
| *bundles = framework_getBundles(context->framework); |
| } |
| |
| framework_logIfError(context->framework->logger, status, NULL, "Failed to get bundles"); |
| |
| return status; |
| } |
| |
| celix_status_t bundleContext_getBundleById(bundle_context_pt context, long id, bundle_pt *bundle) { |
| celix_status_t status = CELIX_SUCCESS; |
| |
| if (context == NULL || *bundle != NULL) { |
| status = CELIX_ILLEGAL_ARGUMENT; |
| } else { |
| *bundle = framework_getBundleById(context->framework, id); |
| if (*bundle == NULL) { |
| status = CELIX_BUNDLE_EXCEPTION; |
| } |
| } |
| |
| framework_logIfError(context->framework->logger, status, NULL, "Failed to get bundle [id=%ld]", id); |
| |
| return status; |
| } |
| |
| celix_status_t bundleContext_addServiceListener(bundle_context_pt context, celix_service_listener_t *listener, const char* filter) { |
| celix_status_t status = CELIX_SUCCESS; |
| |
| if (context != NULL && listener != NULL) { |
| fw_addServiceListener(context->framework, context->bundle, listener, filter); |
| } else { |
| status = CELIX_ILLEGAL_ARGUMENT; |
| } |
| |
| framework_logIfError(context->framework->logger, status, NULL, "Failed to add service listener"); |
| |
| return status; |
| } |
| |
| celix_status_t bundleContext_removeServiceListener(bundle_context_pt context, celix_service_listener_t *listener) { |
| celix_status_t status = CELIX_SUCCESS; |
| |
| if (context != NULL && listener != NULL) { |
| fw_removeServiceListener(context->framework, context->bundle, listener); |
| } else { |
| status = CELIX_ILLEGAL_ARGUMENT; |
| } |
| |
| framework_logIfError(context->framework->logger, status, NULL, "Failed to remove service listener"); |
| |
| return status; |
| } |
| |
| celix_status_t bundleContext_addBundleListener(bundle_context_pt context, bundle_listener_pt listener) { |
| celix_status_t status = CELIX_SUCCESS; |
| |
| if (context != NULL && listener != NULL) { |
| fw_addBundleListener(context->framework, context->bundle, listener); |
| } else { |
| status = CELIX_ILLEGAL_ARGUMENT; |
| } |
| |
| framework_logIfError(context->framework->logger, status, NULL, "Failed to add bundle listener"); |
| |
| return status; |
| } |
| |
| celix_status_t bundleContext_removeBundleListener(bundle_context_pt context, bundle_listener_pt listener) { |
| celix_status_t status = CELIX_SUCCESS; |
| |
| if (context != NULL && listener != NULL) { |
| fw_removeBundleListener(context->framework, context->bundle, listener); |
| } else { |
| status = CELIX_ILLEGAL_ARGUMENT; |
| } |
| |
| framework_logIfError(context->framework->logger, status, NULL, "Failed to remove bundle listener"); |
| |
| return status; |
| } |
| |
| celix_status_t bundleContext_addFrameworkListener(bundle_context_pt context, framework_listener_pt listener) { |
| celix_status_t status = CELIX_SUCCESS; |
| |
| if (context != NULL && listener != NULL) { |
| fw_addFrameworkListener(context->framework, context->bundle, listener); |
| } else { |
| status = CELIX_ILLEGAL_ARGUMENT; |
| } |
| |
| framework_logIfError(context->framework->logger, status, NULL, "Failed to add framework listener"); |
| |
| return status; |
| } |
| |
| celix_status_t bundleContext_removeFrameworkListener(bundle_context_pt context, framework_listener_pt listener) { |
| celix_status_t status = CELIX_SUCCESS; |
| |
| if (context != NULL && listener != NULL) { |
| fw_removeFrameworkListener(context->framework, context->bundle, listener); |
| } else { |
| status = CELIX_ILLEGAL_ARGUMENT; |
| } |
| |
| framework_logIfError(context->framework->logger, status, NULL, "Failed to remove framework listener"); |
| |
| return status; |
| } |
| |
| celix_status_t bundleContext_getProperty(bundle_context_pt context, const char *name, const char** value) { |
| return bundleContext_getPropertyWithDefault(context, name, NULL, value); |
| } |
| |
| celix_status_t bundleContext_getPropertyWithDefault(bundle_context_pt context, const char* name, const char* defaultValue, const char** out) { |
| const char *val = celix_bundleContext_getProperty(context, name, defaultValue); |
| if (out != NULL) { |
| *out = val; |
| } |
| return CELIX_SUCCESS; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| /********************************************************************************************************************** |
| ********************************************************************************************************************** |
| * Updated API |
| ********************************************************************************************************************** |
| **********************************************************************************************************************/ |
| |
| long celix_bundleContext_registerServiceAsync(celix_bundle_context_t *ctx, void *svc, const char *serviceName, celix_properties_t *properties) { |
| celix_service_registration_options_t opts = CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS; |
| opts.svc = svc; |
| opts.serviceName = serviceName; |
| opts.properties = properties; |
| return celix_bundleContext_registerServiceWithOptionsAsync(ctx, &opts); |
| } |
| |
| long celix_bundleContext_registerService(bundle_context_t *ctx, void *svc, const char *serviceName, celix_properties_t *properties) { |
| celix_service_registration_options_t opts = CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS; |
| opts.svc = svc; |
| opts.serviceName = serviceName; |
| opts.properties = properties; |
| return celix_bundleContext_registerServiceWithOptions(ctx, &opts); |
| } |
| |
| |
| long celix_bundleContext_registerServiceFactoryAsync(celix_bundle_context_t *ctx, celix_service_factory_t *factory, const char *serviceName, celix_properties_t *props) { |
| celix_service_registration_options_t opts = CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS; |
| opts.factory = factory; |
| opts.serviceName = serviceName; |
| opts.properties = props; |
| return celix_bundleContext_registerServiceWithOptionsAsync(ctx, &opts); |
| } |
| |
| long celix_bundleContext_registerServiceFactory(celix_bundle_context_t *ctx, celix_service_factory_t *factory, const char *serviceName, celix_properties_t *props) { |
| celix_service_registration_options_t opts = CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS; |
| opts.factory = factory; |
| opts.serviceName = serviceName; |
| opts.properties = props; |
| return celix_bundleContext_registerServiceWithOptions(ctx, &opts); |
| } |
| |
| static long celix_bundleContext_registerServiceWithOptionsInternal(bundle_context_t *ctx, const celix_service_registration_options_t *opts, bool async) { |
| bool valid = opts->serviceName != NULL && strncmp("", opts->serviceName, 1) != 0; |
| if (!valid) { |
| fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Required serviceName argument is NULL or empty"); |
| return -1; |
| } |
| valid = opts->svc != NULL || opts->factory != NULL; |
| if (!valid) { |
| fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Required svc or factory argument is NULL"); |
| return -1; |
| } |
| |
| //set properties |
| celix_properties_t *props = opts->properties; |
| if (props == NULL) { |
| props = celix_properties_create(); |
| } |
| if (opts->serviceVersion != NULL && strncmp("", opts->serviceVersion, 1) != 0) { |
| celix_properties_set(props, CELIX_FRAMEWORK_SERVICE_VERSION, opts->serviceVersion); |
| } |
| const char *lang = opts->serviceLanguage != NULL && strncmp("", opts->serviceLanguage, 1) != 0 ? opts->serviceLanguage : CELIX_FRAMEWORK_SERVICE_C_LANGUAGE; |
| celix_properties_set(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang); |
| |
| long svcId = -1; |
| if (!async && celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) { |
| /* |
| * Note already on event loop, cannot register the service async, because we cannot wait a future event (the |
| * service registration) the event loop. |
| * |
| * So in this case we handle the service registration the "traditional way" and call the sync fw service |
| * registrations versions on the event loop thread |
| */ |
| |
| svcId = celix_framework_registerService(ctx->framework, ctx->bundle, opts->serviceName, opts->svc, opts->factory, props); |
| } else { |
| void (*asyncCallback)(void *data, long serviceId) = async ? opts->asyncCallback : NULL; //NOTE for not async call do not use the callback. |
| svcId = celix_framework_registerServiceAsync(ctx->framework, ctx->bundle, opts->serviceName, opts->svc, opts->factory, props, opts->asyncData, asyncCallback, NULL, NULL); |
| if (!async && svcId >= 0) { |
| //note on event loop thread, but in a sync call, so waiting till service registration is concluded |
| celix_bundleContext_waitForAsyncRegistration(ctx, svcId); |
| } |
| } |
| |
| |
| if (svcId < 0) { |
| properties_destroy(props); |
| } else { |
| celixThreadMutex_lock(&ctx->mutex); |
| celix_arrayList_addLong(ctx->svcRegistrations, svcId); |
| celixThreadMutex_unlock(&ctx->mutex); |
| } |
| return svcId; |
| } |
| |
| long celix_bundleContext_registerServiceWithOptions(bundle_context_t *ctx, const celix_service_registration_options_t *opts) { |
| return celix_bundleContext_registerServiceWithOptionsInternal(ctx, opts, false); |
| } |
| |
| long celix_bundleContext_registerServiceWithOptionsAsync(celix_bundle_context_t *ctx, const celix_service_registration_options_t *opts) { |
| return celix_bundleContext_registerServiceWithOptionsInternal(ctx, opts, true); |
| } |
| |
| void celix_bundleContext_waitForAsyncRegistration(celix_bundle_context_t* ctx, long serviceId) { |
| if (serviceId >= 0) { |
| celix_framework_waitForAsyncRegistration(ctx->framework, serviceId); |
| } |
| } |
| |
| bool celix_bundleContext_isServiceRegistered(celix_bundle_context_t* ctx, long serviceId) { |
| return celix_serviceRegistry_isServiceRegistered(ctx->framework->registry, serviceId); |
| } |
| |
| static void celix_bundleContext_unregisterServiceInternal(celix_bundle_context_t *ctx, long serviceId, bool async, void *data, void (*done)(void*)) { |
| long found = -1L; |
| if (ctx != NULL && serviceId >= 0) { |
| celixThreadMutex_lock(&ctx->mutex); |
| int size = celix_arrayList_size(ctx->svcRegistrations); |
| for (int i = 0; i < size; ++i) { |
| long entryId = celix_arrayList_getLong(ctx->svcRegistrations, i); |
| if (entryId == serviceId) { |
| celix_arrayList_removeAt(ctx->svcRegistrations, i); |
| found = entryId; |
| break; |
| } |
| } |
| celixThreadMutex_unlock(&ctx->mutex); |
| |
| if (found >= 0) { |
| if (async) { |
| celix_framework_unregisterAsync(ctx->framework, ctx->bundle, found, data, done); |
| } else if (celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) { |
| /* |
| * sync unregistration. |
| * Note already on event loop, cannot unregister the service async, because we cannot wait a future event (the |
| * service unregistration) the event loop. |
| * |
| * So in this case we handle the service unregistration the "traditional way" and call the sync fw service |
| * unregistrations versions |
| */ |
| celix_framework_unregister(ctx->framework, ctx->bundle, found); |
| if (done != NULL) { |
| done(data); |
| } |
| } else { |
| celix_framework_unregisterAsync(ctx->framework, ctx->bundle, found, data, done); |
| celix_bundleContext_waitForAsyncUnregistration(ctx, serviceId); |
| } |
| } else { |
| framework_logIfError(ctx->framework->logger, CELIX_ILLEGAL_ARGUMENT, NULL, |
| "No service registered with svc id %li for bundle %s (bundle id: %li)!", serviceId, |
| celix_bundle_getSymbolicName(ctx->bundle), celix_bundle_getId(ctx->bundle)); |
| } |
| } |
| } |
| |
| void celix_bundleContext_unregisterServiceAsync(celix_bundle_context_t *ctx, long serviceId, void *data, void (*done)(void*)) { |
| return celix_bundleContext_unregisterServiceInternal(ctx, serviceId, true, data, done); |
| } |
| |
| void celix_bundleContext_unregisterService(bundle_context_t *ctx, long serviceId) { |
| return celix_bundleContext_unregisterServiceInternal(ctx, serviceId, false, NULL, NULL); |
| } |
| |
| void celix_bundleContext_waitForAsyncUnregistration(celix_bundle_context_t* ctx, long serviceId) { |
| if (serviceId >= 0) { |
| celix_framework_waitForAsyncUnregistration(ctx->framework, serviceId); |
| } |
| } |
| |
| celix_dependency_manager_t* celix_bundleContext_getDependencyManager(bundle_context_t *ctx) { |
| celix_dependency_manager_t* result = NULL; |
| if (ctx != NULL) { |
| celixThreadMutex_lock(&ctx->mutex); |
| if (ctx->mng == NULL) { |
| ctx->mng = celix_private_dependencyManager_create(ctx); |
| } |
| if (ctx->mng == NULL) { |
| framework_logIfError(ctx->framework->logger, CELIX_BUNDLE_EXCEPTION, NULL, "Cannot create dependency manager"); |
| } |
| result = ctx->mng; |
| celixThreadMutex_unlock(&ctx->mutex); |
| } |
| return result; |
| } |
| |
| static celix_status_t bundleContext_bundleChanged(void *listenerSvc, bundle_event_t *event) { |
| celix_status_t status = CELIX_SUCCESS; |
| bundle_listener_t *listener = listenerSvc; |
| celix_bundle_context_bundle_tracker_entry_t *tracker = NULL; |
| if (listener != NULL) { |
| tracker = listener->handle; |
| } |
| |
| bool handleEvent = true; |
| long bndId = celix_bundle_getId(event->bnd); |
| if (bndId == 0 /*framework bundle*/) { |
| handleEvent = tracker->opts.includeFrameworkBundle; |
| } |
| |
| if (tracker != NULL && handleEvent) { |
| void *callbackHandle = tracker->opts.callbackHandle; |
| |
| if (event->type == OSGI_FRAMEWORK_BUNDLE_EVENT_INSTALLED && tracker->opts.onInstalled != NULL) { |
| tracker->opts.onInstalled(callbackHandle, event->bnd); |
| } else if (event->type == OSGI_FRAMEWORK_BUNDLE_EVENT_STARTED && tracker->opts.onStarted != NULL) { |
| tracker->opts.onStarted(callbackHandle, event->bnd); |
| } else if (event->type == OSGI_FRAMEWORK_BUNDLE_EVENT_STOPPING && tracker->opts.onStopped != NULL) { |
| tracker->opts.onStopped(callbackHandle, event->bnd); |
| } |
| |
| if (tracker->opts.onBundleEvent != NULL) { |
| tracker->opts.onBundleEvent(callbackHandle, event); |
| } |
| } |
| return status; |
| } |
| |
| void celix_bundleContext_trackBundlesWithOptionsCallback(void *data) { |
| celix_bundle_context_bundle_tracker_entry_t* entry = data; |
| assert(celix_framework_isCurrentThreadTheEventLoop(entry->ctx->framework)); |
| fw_addBundleListener(entry->ctx->framework, entry->ctx->bundle, &entry->listener); |
| } |
| |
| static long celix_bundleContext_trackBundlesWithOptionsInternal( |
| bundle_context_t* ctx, |
| const celix_bundle_tracking_options_t *opts, |
| bool async) { |
| long trackerId = -1; |
| celix_bundle_context_bundle_tracker_entry_t *entry = calloc(1, sizeof(*entry)); |
| memcpy(&entry->opts, opts, sizeof(*opts)); |
| entry->ctx = ctx; |
| entry->createEventId = celix_framework_nextEventId(ctx->framework); |
| entry->listener.handle = entry; |
| entry->listener.bundleChanged = bundleContext_bundleChanged; |
| |
| celixThreadMutex_lock(&ctx->mutex); |
| entry->trackerId = ctx->nextTrackerId++; |
| hashMap_put(ctx->bundleTrackers, (void*)(entry->trackerId), entry); |
| trackerId = entry->trackerId; |
| celixThreadMutex_unlock(&ctx->mutex); |
| |
| void (*trackerCreatedCallback)(void *trackerCreatedCallbackData) = NULL; |
| if (async) { //note only using the async callback if this is a async call. |
| trackerCreatedCallback = opts->trackerCreatedCallback; |
| } |
| long id = celix_framework_fireGenericEvent( |
| ctx->framework, |
| entry->createEventId, |
| celix_bundle_getId(ctx->bundle), |
| "add bundle listener", |
| entry, |
| celix_bundleContext_trackBundlesWithOptionsCallback, |
| opts->trackerCreatedCallbackData, |
| trackerCreatedCallback); |
| |
| if (!async) { |
| celix_framework_waitForGenericEvent(ctx->framework, id); |
| } |
| |
| return trackerId; |
| } |
| |
| long celix_bundleContext_trackBundlesWithOptions( |
| bundle_context_t* ctx, |
| const celix_bundle_tracking_options_t *opts) { |
| return celix_bundleContext_trackBundlesWithOptionsInternal(ctx, opts, false); |
| } |
| |
| long celix_bundleContext_trackBundlesWithOptionsAsync( |
| celix_bundle_context_t* ctx, |
| const celix_bundle_tracking_options_t *opts) { |
| return celix_bundleContext_trackBundlesWithOptionsInternal(ctx, opts, true); |
| } |
| |
| long celix_bundleContext_trackBundles( |
| bundle_context_t* ctx, |
| void* callbackHandle, |
| void (*onStarted)(void* handle, const bundle_t *bundle), |
| void (*onStopped)(void *handle, const bundle_t *bundle)) { |
| celix_bundle_tracking_options_t opts; |
| memset(&opts, 0, sizeof(opts)); |
| opts.callbackHandle = callbackHandle; |
| opts.onStarted = onStarted; |
| opts.onStopped = onStopped; |
| return celix_bundleContext_trackBundlesWithOptions(ctx, &opts); |
| } |
| |
| long celix_bundleContext_trackBundlesAsync( |
| celix_bundle_context_t* ctx, |
| void* callbackHandle, |
| void (*onStarted)(void* handle, const celix_bundle_t *bundle), |
| void (*onStopped)(void *handle, const celix_bundle_t *bundle)) { |
| celix_bundle_tracking_options_t opts; |
| memset(&opts, 0, sizeof(opts)); |
| opts.callbackHandle = callbackHandle; |
| opts.onStarted = onStarted; |
| opts.onStopped = onStopped; |
| return celix_bundleContext_trackBundlesWithOptionsAsync(ctx, &opts); |
| } |
| |
| void celix_bundleContext_useBundles( |
| bundle_context_t *ctx, |
| void *callbackHandle, |
| void (*use)(void *handle, const bundle_t *bundle)) { |
| celix_framework_useBundles(ctx->framework, false, callbackHandle, use); |
| } |
| |
| bool celix_bundleContext_useBundle( |
| bundle_context_t *ctx, |
| long bundleId, |
| void *callbackHandle, |
| void (*use)(void *handle, const bundle_t *bundle)) { |
| return celix_framework_useBundle(ctx->framework, true, bundleId, callbackHandle, use); |
| } |
| |
| static void bundleContext_cleanupBundleTrackers(bundle_context_t *ctx) { |
| module_pt module; |
| const char *symbolicName; |
| bundle_getCurrentModule(ctx->bundle, &module); |
| module_getSymbolicName(module, &symbolicName); |
| |
| celix_array_list_t* danglingTrkIds = NULL; |
| |
| celixThreadMutex_lock(&ctx->mutex); |
| hash_map_iterator_t iter = hashMapIterator_construct(ctx->bundleTrackers); |
| while (hashMapIterator_hasNext(&iter)) { |
| long trkId = (long)hashMapIterator_nextKey(&iter); |
| fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Dangling bundle tracker with id %li for bundle %s. Add missing 'celix_bundleContext_stopTracker' calls.", trkId, symbolicName); |
| if (danglingTrkIds == NULL) { |
| danglingTrkIds = celix_arrayList_create(); |
| } |
| celix_arrayList_addLong(danglingTrkIds, trkId); |
| } |
| celixThreadMutex_unlock(&ctx->mutex); |
| |
| if (danglingTrkIds != NULL) { |
| for (int i = 0; i < celix_arrayList_size(danglingTrkIds); ++i) { |
| long trkId = celix_arrayList_getLong(danglingTrkIds, i); |
| celix_bundleContext_stopTracker(ctx, trkId); |
| } |
| celix_arrayList_destroy(danglingTrkIds); |
| } |
| } |
| |
| static void bundleContext_cleanupServiceTrackers(bundle_context_t *ctx) { |
| module_pt module; |
| const char *symbolicName; |
| bundle_getCurrentModule(ctx->bundle, &module); |
| module_getSymbolicName(module, &symbolicName); |
| |
| celix_array_list_t* danglingTrkIds = NULL; |
| |
| celixThreadMutex_lock(&ctx->mutex); |
| hash_map_iterator_t iter = hashMapIterator_construct(ctx->serviceTrackers); |
| while (hashMapIterator_hasNext(&iter)) { |
| long trkId = (long)hashMapIterator_nextKey(&iter); |
| celix_bundle_context_service_tracker_entry_t* entry = hashMap_get(ctx->serviceTrackers, (void*)trkId); |
| fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Dangling service tracker with trkId %li, for bundle %s and with filter %s. Add missing 'celix_bundleContext_stopTracker' calls.", trkId, symbolicName, entry->tracker->filter); |
| if (danglingTrkIds == NULL) { |
| danglingTrkIds = celix_arrayList_create(); |
| } |
| celix_arrayList_addLong(danglingTrkIds, trkId); |
| } |
| celixThreadMutex_unlock(&ctx->mutex); |
| |
| if (danglingTrkIds != NULL) { |
| for (int i = 0; i < celix_arrayList_size(danglingTrkIds); ++i) { |
| long trkId = celix_arrayList_getLong(danglingTrkIds, i); |
| celix_bundleContext_stopTracker(ctx, trkId); |
| } |
| celix_arrayList_destroy(danglingTrkIds); |
| } |
| } |
| |
| static void bundleContext_cleanupServiceTrackerTrackers(bundle_context_t *ctx) { |
| module_pt module; |
| const char *symbolicName; |
| bundle_getCurrentModule(ctx->bundle, &module); |
| module_getSymbolicName(module, &symbolicName); |
| |
| celix_array_list_t* danglingTrkIds = NULL; |
| |
| celixThreadMutex_lock(&ctx->mutex); |
| hash_map_iterator_t iter = hashMapIterator_construct(ctx->metaTrackers); |
| while (hashMapIterator_hasNext(&iter)) { |
| long trkId = (long)hashMapIterator_nextKey(&iter); |
| celix_bundle_context_service_tracker_tracker_entry_t *entry = hashMap_get(ctx->metaTrackers, (void*)trkId); |
| fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Dangling meta tracker (service tracker tracker) with trkId %li, for bundle %s and for the services %s. Add missing 'celix_bundleContext_stopTracker' calls.", trkId, symbolicName, entry->serviceName); |
| if (danglingTrkIds == NULL) { |
| danglingTrkIds = celix_arrayList_create(); |
| } |
| celix_arrayList_addLong(danglingTrkIds, trkId); |
| } |
| celixThreadMutex_unlock(&ctx->mutex); |
| |
| if (danglingTrkIds != NULL) { |
| for (int i = 0; i < celix_arrayList_size(danglingTrkIds); ++i) { |
| long trkId = celix_arrayList_getLong(danglingTrkIds, i); |
| celix_bundleContext_stopTracker(ctx, trkId); |
| } |
| celix_arrayList_destroy(danglingTrkIds); |
| } |
| } |
| |
| static void bundleContext_cleanupServiceRegistration(bundle_context_t* ctx) { |
| module_pt module; |
| const char *symbolicName; |
| bundle_getCurrentModule(ctx->bundle, &module); |
| module_getSymbolicName(module, &symbolicName); |
| |
| celix_array_list_t* danglingSvcIds = NULL; |
| |
| celixThreadMutex_lock(&ctx->mutex); |
| for (int i = 0; i < celix_arrayList_size(ctx->svcRegistrations); ++i) { |
| service_registration_pt reg = celix_arrayList_get(ctx->svcRegistrations, i); |
| long svcId = serviceRegistration_getServiceId(reg); |
| const char* svcName = NULL; |
| serviceRegistration_getServiceName(reg, &svcName); |
| fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Dangling service registration with svcId %li, for bundle %s and with service name %s. Add missing 'celix_bundleContext_unregisterService' calls.", svcId, symbolicName, svcName); |
| if (danglingSvcIds == NULL) { |
| danglingSvcIds = celix_arrayList_create(); |
| } |
| celix_arrayList_addLong(danglingSvcIds, svcId); |
| } |
| celixThreadMutex_unlock(&ctx->mutex); |
| |
| if (danglingSvcIds != NULL) { |
| for (int i = 0; i < celix_arrayList_size(danglingSvcIds); ++i) { |
| long svcId = celix_arrayList_getLong(danglingSvcIds, i); |
| celix_bundleContext_unregisterService(ctx, svcId); |
| } |
| celix_arrayList_destroy(danglingSvcIds); |
| } |
| } |
| |
| static void celix_bundleContext_removeBundleTracker(void *data) { |
| celix_bundle_context_bundle_tracker_entry_t *tracker = data; |
| fw_removeBundleListener(tracker->ctx->framework, tracker->ctx->bundle, &tracker->listener); |
| celixThreadMutex_lock(&tracker->ctx->mutex); |
| hashMap_remove(tracker->ctx->stoppingTrackerEventIds, (void*)tracker->trackerId); |
| celixThreadMutex_unlock(&tracker->ctx->mutex); |
| free(tracker); |
| } |
| |
| static void celix_bundleContext_removeServiceTracker(void *data) { |
| celix_bundle_context_service_tracker_entry_t *tracker = data; |
| celix_serviceTracker_destroy(tracker->tracker); |
| celixThreadMutex_lock(&tracker->ctx->mutex); |
| hashMap_remove(tracker->ctx->stoppingTrackerEventIds, (void*)tracker->trackerId); |
| celixThreadMutex_unlock(&tracker->ctx->mutex); |
| free(tracker); |
| } |
| |
| static void celix_bundleContext_removeServiceTrackerTracker(void *data) { |
| celix_bundle_context_service_tracker_tracker_entry_t *tracker = data; |
| celix_framework_unregister(tracker->ctx->framework, tracker->ctx->bundle, tracker->serviceId); |
| celixThreadMutex_lock(&tracker->ctx->mutex); |
| hashMap_remove(tracker->ctx->stoppingTrackerEventIds, (void*)tracker->trackerId); |
| celixThreadMutex_unlock(&tracker->ctx->mutex); |
| free(tracker->serviceName); |
| free(tracker); |
| } |
| |
| static void celix_bundleContext_stopTrackerInternal(bundle_context_t *ctx, long trackerId, bool async, void *doneData, void (*doneCallback)(void* doneData)) { |
| if (ctx == NULL || trackerId <= 0) { |
| return; |
| } |
| |
| bool found = false; |
| celix_bundle_context_bundle_tracker_entry_t *bundleTracker = NULL; |
| celix_bundle_context_service_tracker_entry_t *serviceTracker = NULL; |
| celix_bundle_context_service_tracker_tracker_entry_t *svcTrackerTracker = NULL; |
| |
| celixThreadMutex_lock(&ctx->mutex); |
| |
| if (hashMap_containsKey(ctx->bundleTrackers, (void *) trackerId)) { |
| found = true; |
| bundleTracker = hashMap_remove(ctx->bundleTrackers, (void *) trackerId); |
| } else if (hashMap_containsKey(ctx->serviceTrackers, (void *) trackerId)) { |
| found = true; |
| serviceTracker = hashMap_remove(ctx->serviceTrackers, (void *) trackerId); |
| } else if (hashMap_containsKey(ctx->metaTrackers, (void *) trackerId)) { |
| found = true; |
| svcTrackerTracker = hashMap_remove(ctx->metaTrackers, (void *) trackerId); |
| } |
| |
| if (found && !async && celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) { |
| //already on the event loop, stop tracker "traditionally" to keep old behavior |
| celixThreadMutex_unlock(&ctx->mutex); //note calling remove/stops/unregister out side of locks |
| |
| if (bundleTracker != NULL) { |
| fw_removeBundleListener(ctx->framework, ctx->bundle, &bundleTracker->listener); |
| free(bundleTracker); |
| } else if (serviceTracker != NULL) { |
| celix_serviceTracker_destroy(serviceTracker->tracker); |
| free(serviceTracker); |
| } else if (svcTrackerTracker != NULL) { |
| celix_framework_unregister(ctx->framework, ctx->bundle, svcTrackerTracker->serviceId); |
| free(svcTrackerTracker->serviceName); |
| free(svcTrackerTracker); |
| } |
| |
| if (doneCallback != NULL) { |
| doneCallback(doneData); |
| } |
| } else if (found && async) { |
| //NOTE: for async stopping of tracking we need to ensure we cant wait for the tracker destroy id event. |
| long eventId = celix_framework_nextEventId(ctx->framework); |
| hashMap_put(ctx->stoppingTrackerEventIds, (void*)trackerId, (void*)eventId); |
| |
| if (bundleTracker != NULL) { |
| celix_framework_fireGenericEvent(ctx->framework, eventId, celix_bundle_getId(ctx->bundle), "stop tracker", bundleTracker, celix_bundleContext_removeBundleTracker, doneData, doneCallback); |
| } else if (serviceTracker != NULL) { |
| celix_framework_fireGenericEvent(ctx->framework, eventId, celix_bundle_getId(ctx->bundle), "stop tracker", serviceTracker, celix_bundleContext_removeServiceTracker, doneData, doneCallback); |
| } else if (svcTrackerTracker != NULL) { |
| celix_framework_fireGenericEvent(ctx->framework, eventId, celix_bundle_getId(ctx->bundle), "stop meta tracker", svcTrackerTracker, celix_bundleContext_removeServiceTrackerTracker, doneData, doneCallback); |
| } else { |
| fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Unexpected else branch"); |
| } |
| celixThreadMutex_unlock(&ctx->mutex); |
| } else if (found) { /*sync, so waiting for events*/ |
| long eventId = -1L; |
| if (bundleTracker != NULL) { |
| eventId = celix_framework_fireGenericEvent(ctx->framework, -1L, celix_bundle_getId(ctx->bundle), "stop tracker", bundleTracker, celix_bundleContext_removeBundleTracker, doneData, doneCallback); |
| } else if (serviceTracker != NULL) { |
| eventId = celix_framework_fireGenericEvent(ctx->framework, -1L, celix_bundle_getId(ctx->bundle), "stop tracker", serviceTracker, celix_bundleContext_removeServiceTracker, doneData, doneCallback); |
| } else if (svcTrackerTracker != NULL) { |
| eventId = celix_framework_fireGenericEvent(ctx->framework, -1L, celix_bundle_getId(ctx->bundle), "stop meta tracker", svcTrackerTracker, celix_bundleContext_removeServiceTrackerTracker, doneData, doneCallback); |
| } else { |
| fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Unexpected else branch"); |
| } |
| celixThreadMutex_unlock(&ctx->mutex); |
| celix_framework_waitForGenericEvent(ctx->framework, eventId); |
| } else { |
| celixThreadMutex_unlock(&ctx->mutex); |
| fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "No tracker with id %li found'", trackerId); |
| } |
| } |
| |
| void celix_bundleContext_stopTracker(bundle_context_t *ctx, long trackerId) { |
| return celix_bundleContext_stopTrackerInternal(ctx, trackerId, false, NULL, NULL); |
| } |
| |
| void celix_bundleContext_stopTrackerAsync(celix_bundle_context_t *ctx, long trackerId, void *doneData, void (*doneCallback)(void* doneData)) { |
| return celix_bundleContext_stopTrackerInternal(ctx, trackerId, true, doneData, doneCallback); |
| } |
| |
| static void celix_bundleContext_waitForTrackerInternal(celix_bundle_context_t* ctx, long trackerId, bool waitForStart) { |
| if (ctx == NULL || trackerId < 0) { |
| //silent ignore |
| return; |
| } |
| |
| |
| bool found = false; |
| long eventId = -1; |
| long svcId = -1; |
| |
| if (waitForStart) { |
| celixThreadMutex_lock(&ctx->mutex); |
| if (hashMap_containsKey(ctx->bundleTrackers, (void *) trackerId)) { |
| found = true; |
| celix_bundle_context_bundle_tracker_entry_t* bundleTracker = hashMap_get(ctx->bundleTrackers, (void *) trackerId); |
| eventId = bundleTracker->createEventId; |
| } else if (hashMap_containsKey(ctx->serviceTrackers, (void *) trackerId)) { |
| found = true; |
| celix_bundle_context_service_tracker_entry_t* serviceTracker = hashMap_get(ctx->serviceTrackers, (void *) trackerId); |
| eventId = serviceTracker->createEventId; |
| } else if (hashMap_containsKey(ctx->metaTrackers, (void *) trackerId)) { |
| found = true; |
| celix_bundle_context_service_tracker_tracker_entry_t* svcTrackerTracker = hashMap_get(ctx->metaTrackers, (void *) trackerId); |
| svcId = svcTrackerTracker->serviceId; |
| } |
| celixThreadMutex_unlock(&ctx->mutex); |
| } else { |
| celixThreadMutex_lock(&ctx->mutex); |
| if (hashMap_containsKey(ctx->stoppingTrackerEventIds, (void*)trackerId)) { |
| found = true; |
| eventId = (long)hashMap_get(ctx->stoppingTrackerEventIds, (void*)trackerId); |
| } |
| celixThreadMutex_unlock(&ctx->mutex); |
| } |
| |
| if (found) { |
| if (svcId >= 0 && waitForStart) { |
| celix_framework_waitForAsyncRegistration(ctx->framework, svcId); |
| } else if (svcId >= 0) { |
| celix_framework_waitForAsyncUnregistration(ctx->framework, svcId); |
| } else { |
| celix_framework_waitForGenericEvent(ctx->framework, eventId); |
| } |
| } |
| } |
| |
| |
| void celix_bundleContext_waitForAsyncTracker(celix_bundle_context_t* ctx, long trackerId) { |
| return celix_bundleContext_waitForTrackerInternal(ctx, trackerId, true); |
| } |
| |
| void celix_bundleContext_waitForAsyncStopTracker(celix_bundle_context_t* ctx, long trackerId) { |
| return celix_bundleContext_waitForTrackerInternal(ctx, trackerId, false); |
| } |
| |
| long celix_bundleContext_installBundle(bundle_context_t *ctx, const char *bundleLoc, bool autoStart) { |
| return celix_framework_installBundle(ctx->framework, bundleLoc, autoStart); |
| } |
| |
| static void bundleContext_listBundlesCallback(void *handle, const bundle_t *c_bnd) { |
| celix_array_list_t* ids = handle; |
| long id = celix_bundle_getId(c_bnd); |
| if (id > 0) { //note skipping framework bundle id (0) |
| celix_arrayList_addLong(ids, id); |
| } |
| } |
| |
| celix_array_list_t* celix_bundleContext_listBundles(celix_bundle_context_t *ctx) { |
| celix_array_list_t *result = celix_arrayList_create(); |
| celix_bundleContext_useBundles(ctx, result, bundleContext_listBundlesCallback); |
| return result; |
| } |
| |
| bool celix_bundleContext_isBundleInstalled(celix_bundle_context_t *ctx, long bndId) { |
| return celix_framework_isBundleInstalled(ctx->framework, bndId); |
| } |
| |
| bool celix_bundleContext_isBundleActive(celix_bundle_context_t *ctx, long bndId) { |
| return celix_framework_isBundleActive(ctx->framework, bndId); |
| } |
| |
| bool celix_bundleContext_startBundle(celix_bundle_context_t *ctx, long bundleId) { |
| return celix_framework_startBundle(ctx->framework, bundleId); |
| } |
| |
| |
| bool celix_bundleContext_stopBundle(celix_bundle_context_t *ctx, long bundleId) { |
| return celix_framework_stopBundle(ctx->framework, bundleId); |
| } |
| |
| bool celix_bundleContext_uninstallBundle(bundle_context_t *ctx, long bundleId) { |
| return celix_framework_uninstallBundle(ctx->framework, bundleId); |
| } |
| |
| bool celix_bundleContext_useServiceWithId( |
| bundle_context_t *ctx, |
| long serviceId, |
| const char *serviceName, |
| void *callbackHandle, |
| void (*use)(void *handle, void *svc)) { |
| celix_service_use_options_t opts = CELIX_EMPTY_SERVICE_USE_OPTIONS; |
| |
| char filter[64]; |
| snprintf(filter, 64, "(%s=%li)", OSGI_FRAMEWORK_SERVICE_ID, serviceId); |
| |
| opts.filter.serviceName = serviceName; |
| opts.filter.filter = filter; |
| opts.callbackHandle = callbackHandle; |
| opts.use = use; |
| return celix_bundleContext_useServiceWithOptions(ctx, &opts); |
| } |
| |
| bool celix_bundleContext_useService( |
| bundle_context_t *ctx, |
| const char* serviceName, |
| void *callbackHandle, |
| void (*use)(void *handle, void *svc)) { |
| celix_service_use_options_t opts = CELIX_EMPTY_SERVICE_USE_OPTIONS; |
| opts.filter.serviceName = serviceName; |
| opts.callbackHandle = callbackHandle; |
| opts.use = use; |
| return celix_bundleContext_useServiceWithOptions(ctx, &opts); |
| } |
| |
| |
| size_t celix_bundleContext_useServices( |
| bundle_context_t *ctx, |
| const char* serviceName, |
| void *callbackHandle, |
| void (*use)(void *handle, void *svc)) { |
| celix_service_use_options_t opts = CELIX_EMPTY_SERVICE_USE_OPTIONS; |
| opts.filter.serviceName = serviceName; |
| opts.callbackHandle = callbackHandle; |
| opts.use = use; |
| return celix_bundleContext_useServicesWithOptions(ctx, &opts); |
| } |
| |
| typedef struct celix_bundle_context_use_service_data { |
| celix_bundle_context_t* ctx; |
| celix_service_use_options_t opts; |
| |
| celix_thread_mutex_t mutex; //protects below |
| bool called; |
| size_t count; |
| celix_service_tracker_t * svcTracker; |
| } celix_bundle_context_use_service_data_t; |
| |
| static void celix_bundleContext_useServiceWithOptions_1_CreateServiceTracker(void *data) { |
| celix_bundle_context_use_service_data_t* d = data; |
| assert(celix_framework_isCurrentThreadTheEventLoop(d->ctx->framework)); |
| |
| celix_service_tracking_options_t trkOpts = CELIX_EMPTY_SERVICE_TRACKING_OPTIONS; |
| trkOpts.filter.serviceName = d->opts.filter.serviceName; |
| trkOpts.filter = d->opts.filter; |
| trkOpts.filter.versionRange = d->opts.filter.versionRange; |
| trkOpts.filter.serviceLanguage = d->opts.filter.serviceLanguage; |
| |
| celixThreadMutex_lock(&d->mutex); |
| d->svcTracker = celix_serviceTracker_createWithOptions(d->ctx, &trkOpts); |
| celixThreadMutex_unlock(&d->mutex); |
| } |
| |
| static void celix_bundleContext_useServiceWithOptions_2_UseService(void *data) { |
| celix_bundle_context_use_service_data_t* d = data; |
| assert(celix_framework_isCurrentThreadTheEventLoop(d->ctx->framework)); |
| |
| celixThreadMutex_lock(&d->mutex); |
| celix_service_tracker_t *tracker = d->svcTracker; |
| d->svcTracker = NULL; |
| celixThreadMutex_unlock(&d->mutex); |
| |
| bool called = celix_serviceTracker_useHighestRankingService(tracker, d->opts.filter.serviceName, d->opts.callbackHandle, d->opts.use, d->opts.useWithProperties, d->opts.useWithOwner); |
| celix_serviceTracker_destroy(tracker); |
| |
| celixThreadMutex_lock(&d->mutex); |
| d->called = called; |
| celixThreadMutex_unlock(&d->mutex); |
| } |
| |
| bool celix_bundleContext_useServiceWithOptions( |
| celix_bundle_context_t *ctx, |
| const celix_service_use_options_t *opts) { |
| if (opts == NULL) { |
| return false; |
| } |
| |
| celix_bundle_context_use_service_data_t data = {0}; |
| data.ctx = ctx; |
| data.opts = *opts; |
| celixThreadMutex_create(&data.mutex, NULL); |
| |
| struct timespec startTime = celix_gettime(CLOCK_MONOTONIC); |
| |
| bool useServiceIsDone = false; |
| do { |
| if (celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) { |
| celix_bundleContext_useServiceWithOptions_1_CreateServiceTracker(&data); |
| celix_bundleContext_useServiceWithOptions_2_UseService(&data); |
| } else { |
| long eventId = celix_framework_fireGenericEvent(ctx->framework, -1, celix_bundle_getId(ctx->bundle), "create service tracker", &data, celix_bundleContext_useServiceWithOptions_1_CreateServiceTracker, NULL, NULL); |
| celix_framework_waitForGenericEvent(ctx->framework, eventId); |
| |
| eventId = celix_framework_fireGenericEvent(ctx->framework, -1, celix_bundle_getId(ctx->bundle), "use service", &data, celix_bundleContext_useServiceWithOptions_2_UseService, NULL, NULL); |
| celix_framework_waitForGenericEvent(ctx->framework, eventId); |
| } |
| |
| bool timeoutNotUsed = opts->waitTimeoutInSeconds == 0; |
| bool timeoutExpired = celix_elapsedtime(CLOCK_MONOTONIC, startTime) > opts->waitTimeoutInSeconds; |
| celixThreadMutex_lock(&data.mutex); |
| bool called = data.called; |
| celixThreadMutex_unlock(&data.mutex); |
| |
| useServiceIsDone = timeoutNotUsed || timeoutExpired || called; |
| if (!useServiceIsDone) { |
| usleep(10); |
| } |
| } while (!useServiceIsDone); |
| |
| celixThreadMutex_lock(&data.mutex); |
| bool called = data.called; |
| celixThreadMutex_unlock(&data.mutex); |
| celixThreadMutex_destroy(&data.mutex); |
| |
| return called; |
| } |
| |
| static void celix_bundleContext_useServicesWithOptions_1_CreateServiceTracker(void *data) { |
| celix_bundle_context_use_service_data_t* d = data; |
| assert(celix_framework_isCurrentThreadTheEventLoop(d->ctx->framework)); |
| |
| celix_service_tracking_options_t trkOpts = CELIX_EMPTY_SERVICE_TRACKING_OPTIONS; |
| trkOpts.filter.serviceName = d->opts.filter.serviceName; |
| trkOpts.filter = d->opts.filter; |
| trkOpts.filter.versionRange = d->opts.filter.versionRange; |
| trkOpts.filter.serviceLanguage = d->opts.filter.serviceLanguage; |
| |
| celixThreadMutex_lock(&d->mutex); |
| d->svcTracker = celix_serviceTracker_createWithOptions(d->ctx, &trkOpts); |
| celixThreadMutex_unlock(&d->mutex); |
| } |
| |
| static void celix_bundleContext_useServicesWithOptions_2_UseServices(void *data) { |
| celix_bundle_context_use_service_data_t* d = data; |
| assert(celix_framework_isCurrentThreadTheEventLoop(d->ctx->framework)); |
| |
| celixThreadMutex_lock(&d->mutex); |
| celix_service_tracker_t *tracker = d->svcTracker; |
| d->svcTracker = NULL; |
| celixThreadMutex_unlock(&d->mutex); |
| |
| size_t count = celix_serviceTracker_useServices(tracker, d->opts.filter.serviceName, d->opts.callbackHandle, d->opts.use, d->opts.useWithProperties, d->opts.useWithOwner); |
| celix_serviceTracker_destroy(tracker); |
| |
| celixThreadMutex_lock(&d->mutex); |
| d->count = count; |
| celixThreadMutex_unlock(&d->mutex); |
| } |
| |
| size_t celix_bundleContext_useServicesWithOptions( |
| celix_bundle_context_t *ctx, |
| const celix_service_use_options_t *opts) { |
| if (opts == NULL) { |
| return 0; |
| } |
| |
| celix_bundle_context_use_service_data_t data = {0}; |
| data.ctx = ctx; |
| data.opts = *opts; |
| |
| if (celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) { |
| celix_bundleContext_useServicesWithOptions_1_CreateServiceTracker(&data); |
| celix_bundleContext_useServicesWithOptions_2_UseServices(&data); |
| } else { |
| long eventId = celix_framework_fireGenericEvent(ctx->framework, -1, celix_bundle_getId(ctx->bundle), "create service tracker", &data, celix_bundleContext_useServicesWithOptions_1_CreateServiceTracker, NULL, NULL); |
| celix_framework_waitForGenericEvent(ctx->framework, eventId); |
| |
| eventId = celix_framework_fireGenericEvent(ctx->framework, -1, celix_bundle_getId(ctx->bundle), "use service", &data, celix_bundleContext_useServicesWithOptions_2_UseServices, NULL, NULL); |
| celix_framework_waitForGenericEvent(ctx->framework, eventId); |
| } |
| |
| celixThreadMutex_lock(&data.mutex); |
| size_t count = data.count; |
| celixThreadMutex_unlock(&data.mutex); |
| celixThreadMutex_destroy(&data.mutex); |
| |
| return count; |
| } |
| |
| |
| long celix_bundleContext_trackService( |
| bundle_context_t* ctx, |
| const char* serviceName, |
| void* callbackHandle, |
| void (*set)(void* handle, void* svc)) { |
| celix_service_tracking_options_t opts = CELIX_EMPTY_SERVICE_TRACKING_OPTIONS; |
| opts.filter.serviceName = serviceName; |
| opts.callbackHandle = callbackHandle; |
| opts.set = set; |
| return celix_bundleContext_trackServicesWithOptionsInternal(ctx, &opts, false); |
| } |
| |
| long celix_bundleContext_trackServiceAsync( |
| bundle_context_t* ctx, |
| const char* serviceName, |
| void* callbackHandle, |
| void (*set)(void* handle, void* svc)) { |
| celix_service_tracking_options_t opts = CELIX_EMPTY_SERVICE_TRACKING_OPTIONS; |
| opts.filter.serviceName = serviceName; |
| opts.callbackHandle = callbackHandle; |
| opts.set = set; |
| return celix_bundleContext_trackServicesWithOptionsInternal(ctx, &opts, true); |
| } |
| |
| |
| long celix_bundleContext_trackServices( |
| bundle_context_t* ctx, |
| const char* serviceName, |
| void* callbackHandle, |
| void (*add)(void* handle, void* svc), |
| void (*remove)(void* handle, void* svc)) { |
| celix_service_tracking_options_t opts = CELIX_EMPTY_SERVICE_TRACKING_OPTIONS; |
| opts.filter.serviceName = serviceName; |
| opts.callbackHandle = callbackHandle; |
| opts.add = add; |
| opts.remove = remove; |
| return celix_bundleContext_trackServicesWithOptionsInternal(ctx, &opts, false); |
| } |
| |
| long celix_bundleContext_trackServicesAsync( |
| celix_bundle_context_t* ctx, |
| const char* serviceName, |
| void* callbackHandle, |
| void (*add)(void* handle, void* svc), |
| void (*remove)(void* handle, void* svc)) { |
| celix_service_tracking_options_t opts = CELIX_EMPTY_SERVICE_TRACKING_OPTIONS; |
| opts.filter.serviceName = serviceName; |
| opts.callbackHandle = callbackHandle; |
| opts.add = add; |
| opts.remove = remove; |
| return celix_bundleContext_trackServicesWithOptionsInternal(ctx, &opts, true); |
| } |
| |
| |
| static void celix_bundleContext_createTrackerOnEventLoop(void *data) { |
| celix_bundle_context_service_tracker_entry_t* entry = data; |
| assert(celix_framework_isCurrentThreadTheEventLoop(entry->ctx->framework)); |
| celix_service_tracker_t *tracker = celix_serviceTracker_createWithOptions(entry->ctx, &entry->opts); |
| if (tracker != NULL) { |
| celixThreadMutex_lock(&entry->ctx->mutex); |
| entry->tracker = tracker; |
| celixThreadMutex_unlock(&entry->ctx->mutex); |
| } else { |
| fw_log(entry->ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Cannot create tracker for bnd %s (%li)", celix_bundle_getSymbolicName(entry->ctx->bundle), celix_bundle_getId(entry->ctx->bundle)); |
| } |
| } |
| |
| static void celix_bundleContext_doneCreatingTrackerOnEventLoop(void *data) { |
| celix_bundle_context_service_tracker_entry_t* entry = data; |
| if (entry->trackerCreatedCallback != NULL) { |
| entry->trackerCreatedCallback(entry->trackerCreatedCallbackData); |
| } |
| } |
| |
| |
| |
| static long celix_bundleContext_trackServicesWithOptionsInternal(celix_bundle_context_t *ctx, const celix_service_tracking_options_t *opts, bool async) { |
| if (ctx == NULL) { |
| return -1L; |
| } else if (opts == NULL) { |
| fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Cannot track services with a NULL service tracking options argument"); |
| return -1L; |
| } |
| |
| if (opts->filter.serviceName == NULL) { |
| fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_DEBUG, "Starting a tracker for any services"); |
| } |
| |
| if (!async && celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) { |
| //already in event loop thread. To keep the old behavior just create the tracker traditionally (chained in the current thread). |
| celix_service_tracker_t *tracker = celix_serviceTracker_createWithOptions(ctx, opts); |
| long trackerId = -1L; |
| if (tracker != NULL) { |
| celix_bundle_context_service_tracker_entry_t* entry = calloc(1, sizeof(*entry)); |
| entry->ctx = ctx; |
| entry->tracker = tracker; |
| entry->opts = *opts; |
| entry->createEventId = -1; |
| celixThreadMutex_lock(&ctx->mutex); |
| entry->trackerId = ctx->nextTrackerId++; |
| trackerId = entry->trackerId; |
| hashMap_put(ctx->serviceTrackers, (void *) trackerId, entry); |
| celixThreadMutex_unlock(&ctx->mutex); |
| } |
| return trackerId; |
| } else { |
| celix_bundle_context_service_tracker_entry_t* entry = calloc(1, sizeof(*entry)); |
| entry->ctx = ctx; |
| entry->createEventId = celix_framework_nextEventId(ctx->framework); |
| entry->tracker = NULL; //will be set async |
| entry->opts = *opts; |
| if (async) { //note only setting the async callback if this is a async call |
| entry->trackerCreatedCallbackData = opts->trackerCreatedCallbackData; |
| entry->trackerCreatedCallback = opts->trackerCreatedCallback; |
| } |
| celixThreadMutex_lock(&ctx->mutex); |
| entry->trackerId = ctx->nextTrackerId++; |
| long trackerId = entry->trackerId; |
| hashMap_put(ctx->serviceTrackers, (void *)entry->trackerId, entry); |
| celixThreadMutex_unlock(&ctx->mutex); |
| |
| long id = celix_framework_fireGenericEvent(ctx->framework, entry->createEventId, celix_bundle_getId(ctx->bundle), "create service tracker event", entry, celix_bundleContext_createTrackerOnEventLoop, entry, celix_bundleContext_doneCreatingTrackerOnEventLoop); |
| |
| if (!async) { |
| celix_framework_waitForGenericEvent(ctx->framework, id); |
| } |
| |
| return trackerId; |
| } |
| } |
| |
| long celix_bundleContext_trackServicesWithOptions(celix_bundle_context_t *ctx, const celix_service_tracking_options_t *opts) { |
| return celix_bundleContext_trackServicesWithOptionsInternal(ctx, opts, false); |
| } |
| |
| long celix_bundleContext_trackServicesWithOptionsAsync(celix_bundle_context_t *ctx, const celix_service_tracking_options_t *opts) { |
| return celix_bundleContext_trackServicesWithOptionsInternal(ctx, opts, true); |
| } |
| |
| long celix_bundleContext_findService(celix_bundle_context_t *ctx, const char *serviceName) { |
| celix_service_filter_options_t opts = CELIX_EMPTY_SERVICE_FILTER_OPTIONS; |
| opts.serviceName = serviceName; |
| return celix_bundleContext_findServiceWithOptions(ctx, &opts); |
| } |
| |
| long celix_bundleContext_findServiceWithOptions(celix_bundle_context_t *ctx, const celix_service_filter_options_t *opts) { |
| long result = -1L; |
| char* filter = celix_serviceRegistry_createFilterFor(ctx->framework->registry, opts->serviceName, opts->versionRange, opts->filter, opts->serviceLanguage, opts->ignoreServiceLanguage); |
| if (filter != NULL) { |
| celix_array_list_t *svcIds = celix_serviceRegisrty_findServices(ctx->framework->registry, filter); |
| if (svcIds != NULL && celix_arrayList_size(svcIds) > 0) { |
| result = celix_arrayList_getLong(svcIds, 0); |
| } |
| if (svcIds != NULL) { |
| celix_arrayList_destroy(svcIds); |
| } |
| free(filter); |
| } |
| return result; |
| } |
| |
| |
| celix_array_list_t* celix_bundleContext_findServices(celix_bundle_context_t *ctx, const char *serviceName) { |
| celix_service_filter_options_t opts = CELIX_EMPTY_SERVICE_FILTER_OPTIONS; |
| opts.serviceName = serviceName; |
| return celix_bundleContext_findServicesWithOptions(ctx, &opts); |
| } |
| |
| celix_array_list_t* celix_bundleContext_findServicesWithOptions(celix_bundle_context_t *ctx, const celix_service_filter_options_t *opts) { |
| celix_array_list_t* result = NULL; |
| char* filter = celix_serviceRegistry_createFilterFor(ctx->framework->registry, opts->serviceName, opts->versionRange, opts->filter, opts->serviceLanguage, opts->ignoreServiceLanguage); |
| if (filter != NULL) { |
| result = celix_serviceRegisrty_findServices(ctx->framework->registry, filter); |
| free(filter); |
| } |
| return result; |
| } |
| |
| static celix_status_t bundleContext_callServicedTrackerTrackerCallback(void *handle, celix_array_list_t *listeners, bool add) { |
| celix_bundle_context_service_tracker_tracker_entry_t *entry = handle; |
| if (entry != NULL) { |
| size_t size = celix_arrayList_size(listeners); |
| for (unsigned int i = 0; i < size; ++i) { |
| listener_hook_info_pt info = arrayList_get(listeners, i); |
| celix_bundle_t *bnd = NULL; |
| bundleContext_getBundle(info->context, &bnd); |
| |
| celix_service_tracker_info_t trkInfo; |
| memset(&trkInfo, 0, sizeof(trkInfo)); |
| trkInfo.bundleId = celix_bundle_getId(bnd); |
| trkInfo.filter = celix_filter_create(info->filter); |
| trkInfo.serviceName = celix_filter_findAttribute(trkInfo.filter, OSGI_FRAMEWORK_OBJECTCLASS); |
| trkInfo.serviceLanguage = celix_filter_findAttribute(trkInfo.filter, CELIX_FRAMEWORK_SERVICE_LANGUAGE); |
| const char *filterSvcName = celix_filter_findAttribute(trkInfo.filter, OSGI_FRAMEWORK_OBJECTCLASS); |
| |
| bool match = entry->serviceName == NULL || (filterSvcName != NULL && strncmp(filterSvcName, entry->serviceName, 1024*1024) == 0); |
| |
| if (add && entry->add != NULL && match) { |
| entry->add(entry->callbackHandle, &trkInfo); |
| } else if (!add && entry->remove != NULL && match) { |
| entry->remove(entry->callbackHandle, &trkInfo); |
| } |
| celix_filter_destroy(trkInfo.filter); |
| } |
| } |
| return CELIX_SUCCESS; |
| } |
| |
| static celix_status_t bundleContext_callServicedTrackerTrackerAdd(void *handle, celix_array_list_t *listeners) { |
| return bundleContext_callServicedTrackerTrackerCallback(handle, listeners, true); |
| } |
| |
| static celix_status_t bundleContext_callServicedTrackerTrackerRemove(void *handle, celix_array_list_t *listeners) { |
| return bundleContext_callServicedTrackerTrackerCallback(handle, listeners, false); |
| } |
| |
| long celix_bundleContext_trackServiceTrackersInternal( |
| celix_bundle_context_t *ctx, |
| const char *serviceName, |
| void *callbackHandle, |
| void (*trackerAdd)(void *handle, const celix_service_tracker_info_t *info), |
| void (*trackerRemove)(void *handle, const celix_service_tracker_info_t *info), |
| bool async, |
| void *doneData, |
| void (*doneCallback)(void*)) { |
| if (serviceName == NULL) { |
| fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_DEBUG, "Note starting a meta tracker for all services", __FUNCTION__); |
| } |
| |
| celix_bundle_context_service_tracker_tracker_entry_t *entry = calloc(1, sizeof(*entry)); |
| celixThreadMutex_lock(&ctx->mutex); |
| entry->trackerId = ctx->nextTrackerId++; |
| celixThreadMutex_unlock(&ctx->mutex); |
| entry->ctx = ctx; |
| entry->callbackHandle = callbackHandle; |
| entry->add = trackerAdd; |
| entry->remove = trackerRemove; |
| entry->serviceName = celix_utils_strdup(serviceName); |
| entry->hook.handle = entry; |
| entry->hook.added = bundleContext_callServicedTrackerTrackerAdd; |
| entry->hook.removed = bundleContext_callServicedTrackerTrackerRemove; |
| |
| if (!async && celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) { |
| //already on event loop, registering the "traditional way" i.e. chaining on the current thread |
| service_registration_t* reg = NULL; |
| bundleContext_registerService(ctx, OSGI_FRAMEWORK_LISTENER_HOOK_SERVICE_NAME, &entry->hook, NULL, ®); |
| entry->serviceId = serviceRegistration_getServiceId(reg); |
| } else if (async) { |
| entry->serviceId = celix_framework_registerServiceAsync(ctx->framework, ctx->bundle, OSGI_FRAMEWORK_LISTENER_HOOK_SERVICE_NAME, &entry->hook, NULL, NULL, NULL, NULL, doneData, doneCallback); |
| } else { |
| entry->serviceId = celix_framework_registerServiceAsync(ctx->framework, ctx->bundle, OSGI_FRAMEWORK_LISTENER_HOOK_SERVICE_NAME, &entry->hook, NULL, NULL, NULL, NULL, doneData, doneCallback); |
| celix_framework_waitForAsyncRegistration(ctx->framework, entry->serviceId); |
| } |
| |
| if (entry->serviceId >= 0) { |
| celixThreadMutex_lock(&ctx->mutex); |
| hashMap_put(ctx->metaTrackers, (void*)entry->trackerId, entry); |
| long trkId = entry->trackerId; |
| celixThreadMutex_unlock(&ctx->mutex); |
| return trkId; |
| } else { |
| framework_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__, "Error registering service listener hook for service tracker tracker\n"); |
| free(entry); |
| return -1L; |
| } |
| } |
| |
| long celix_bundleContext_trackServiceTrackers( |
| celix_bundle_context_t *ctx, |
| const char *serviceName, |
| void *callbackHandle, |
| void (*trackerAdd)(void *handle, const celix_service_tracker_info_t *info), |
| void (*trackerRemove)(void *handle, const celix_service_tracker_info_t *info)) { |
| return celix_bundleContext_trackServiceTrackersInternal(ctx, serviceName, callbackHandle, trackerAdd, trackerRemove, false, NULL, NULL); |
| } |
| |
| long celix_bundleContext_trackServiceTrackersAsync( |
| celix_bundle_context_t *ctx, |
| const char *serviceName, |
| void *callbackHandle, |
| void (*trackerAdd)(void *handle, const celix_service_tracker_info_t *info), |
| void (*trackerRemove)(void *handle, const celix_service_tracker_info_t *info), |
| void *doneCallbackData, |
| void (*doneCallback)(void* doneCallbackData)) { |
| return celix_bundleContext_trackServiceTrackersInternal(ctx, serviceName, callbackHandle, trackerAdd, trackerRemove, true, doneCallbackData, doneCallback); |
| } |
| |
| void celix_bundleContext_waitForEvents(celix_bundle_context_t* ctx) { |
| celix_framework_waitUntilNoEventsForBnd(ctx->framework, celix_bundle_getId(ctx->bundle)); |
| } |
| |
| celix_bundle_t* celix_bundleContext_getBundle(const celix_bundle_context_t *ctx) { |
| celix_bundle_t *bnd = NULL; |
| if (ctx != NULL) { |
| bnd = ctx->bundle; |
| } |
| return bnd; |
| } |
| |
| celix_framework_t* celix_bundleContext_getFramework(const celix_bundle_context_t *ctx) { |
| celix_framework_t *fw = NULL; |
| if (ctx != NULL) { |
| fw = ctx->framework; |
| } |
| return fw; |
| } |
| |
| |
| const char* celix_bundleContext_getProperty(celix_bundle_context_t *ctx, const char *key, const char *defaultVal) { |
| const char *val = NULL; |
| if (ctx != NULL) { |
| fw_getProperty(ctx->framework, key, defaultVal, &val); |
| } |
| return val; |
| } |
| |
| long celix_bundleContext_getPropertyAsLong(celix_bundle_context_t *ctx, const char *key, long defaultValue) { |
| long result = defaultValue; |
| const char *val = celix_bundleContext_getProperty(ctx, key, NULL); |
| if (val != NULL) { |
| char *enptr = NULL; |
| errno = 0; |
| long r = strtol(val, &enptr, 10); |
| if (enptr != val && errno == 0) { |
| result = r; |
| } |
| } |
| return result; |
| } |
| |
| double celix_bundleContext_getPropertyAsDouble(celix_bundle_context_t *ctx, const char *key, double defaultValue) { |
| double result = defaultValue; |
| const char *val = celix_bundleContext_getProperty(ctx, key, NULL); |
| if (val != NULL) { |
| char *enptr = NULL; |
| errno = 0; |
| double r = strtod(val, &enptr); |
| if (enptr != val && errno == 0) { |
| result = r; |
| } |
| } |
| return result; |
| } |
| |
| |
| bool celix_bundleContext_getPropertyAsBool(celix_bundle_context_t *ctx, const char *key, bool defaultValue) { |
| bool result = defaultValue; |
| const char *val = celix_bundleContext_getProperty(ctx, key, NULL); |
| if (val != NULL) { |
| char buf[32]; |
| snprintf(buf, 32, "%s", val); |
| char *trimmed = utils_stringTrim(buf); |
| if (strncasecmp("true", trimmed, strlen("true")) == 0) { |
| result = true; |
| } else if (strncasecmp("false", trimmed, strlen("false")) == 0) { |
| result = false; |
| } |
| } |
| return result; |
| } |
| |
| static void celix_bundleContext_getBundleSymbolicNameCallback(void *data, const celix_bundle_t *bnd) { |
| char **out = data; |
| *out = celix_utils_strdup(celix_bundle_getSymbolicName(bnd)); |
| } |
| |
| char* celix_bundleContext_getBundleSymbolicName(celix_bundle_context_t *ctx, long bndId) { |
| char *name = NULL; |
| celix_framework_useBundle(ctx->framework, false, bndId, &name, celix_bundleContext_getBundleSymbolicNameCallback); |
| return name; |
| } |