static void celix_bundleContext_stopTrackerInternal()

in libs/framework/src/bundle_context.c [917:1015]


static void celix_bundleContext_stopTrackerInternal(celix_bundle_context_t* ctx, long trackerId, bool async, void *doneData, void (*doneCallback)(void* doneData)) {
    if (ctx == NULL || trackerId <= 0) {
        return;
    }

    bool found = false;
    bool cancelled = 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;

    celixThreadRwlock_writeLock(&ctx->lock);

    if (celix_longHashMap_hasKey(ctx->bundleTrackers, trackerId)) {
        found = true;
        bundleTracker = celix_longHashMap_get(ctx->bundleTrackers, trackerId);
        (void)celix_longHashMap_remove(ctx->bundleTrackers, trackerId);
        if (!bundleTracker->created && !async) {
            //note tracker not yet created, so cancel instead of removing
            bundleTracker->cancelled = true;
            cancelled = true;
        }
    } else if (celix_longHashMap_hasKey(ctx->serviceTrackers, trackerId)) {
        found = true;
        serviceTracker = celix_longHashMap_get(ctx->serviceTrackers, trackerId);
        (void)celix_longHashMap_remove(ctx->serviceTrackers, trackerId);
        if (serviceTracker->tracker == NULL && !async) {
            //note tracker not yet created, so cancel instead of removing
            serviceTracker->cancelled = true;
            cancelled = true;
        }
    } else if (celix_longHashMap_hasKey(ctx->metaTrackers, trackerId)) {
        found = true;
        svcTrackerTracker = celix_longHashMap_get(ctx->metaTrackers, trackerId);
        (void)celix_longHashMap_remove(ctx->metaTrackers, trackerId);
        //note because a meta tracker is a service listener hook under waiter, no additional cancel is needed (svc reg will be cancelled)
    }

    if (found && cancelled) {
        //nop
        celixThreadRwlock_unlock(&ctx->lock);
    } else if (found && !async && celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) {
        //already on the event loop, stop tracker "traditionally" to keep old behavior
        celixThreadRwlock_unlock(&ctx->lock); //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_bundleContext_waitForUnusedServiceTracker(ctx, serviceTracker);
            celix_serviceTracker_destroy(serviceTracker->tracker);
            if (serviceTracker->isFreeFilterNeeded) {
                free((char*)serviceTracker->opts.filter.serviceName);
                free((char*)serviceTracker->opts.filter.versionRange);
                free((char*)serviceTracker->opts.filter.filter);
            }
            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);
        celix_longHashMap_put(ctx->stoppingTrackerEventIds, 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");
        }
        celixThreadRwlock_unlock(&ctx->lock);
    } 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");
        }
        celixThreadRwlock_unlock(&ctx->lock);
        celix_framework_waitForGenericEvent(ctx->framework, eventId);
    } else {
        celixThreadRwlock_unlock(&ctx->lock);
        fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "No tracker with id %li found'", trackerId);
    }
}