http://git-wip-us.apache.org/repos/asf/celix/blob/a1c30887/framework/src/framework.c ---------------------------------------------------------------------- diff --git a/framework/src/framework.c b/framework/src/framework.c new file mode 100644 index 0000000..b1db384 --- /dev/null +++ b/framework/src/framework.c @@ -0,0 +1,2620 @@ +/** + *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. + */ +/* + * framework.c + * + * \date Mar 23, 2010 + * \author <a href="mailto:[email protected]">Apache Celix Project Team</a> + * \copyright Apache License, Version 2.0 + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include "celixbool.h" + +#ifdef _WIN32 +#include <winbase.h> +#include <windows.h> +#else +#include <dlfcn.h> +#endif +#include <uuid/uuid.h> + +#include "framework_private.h" +#include "constants.h" +#include "resolver.h" +#include "utils.h" +#include "linked_list_iterator.h" +#include "service_reference_private.h" +#include "listener_hook_service.h" +#include "service_registration_private.h" + +typedef celix_status_t (*create_function_pt)(bundle_context_pt context, void **userData); +typedef celix_status_t (*start_function_pt)(void * handle, bundle_context_pt context); +typedef celix_status_t (*stop_function_pt)(void * handle, bundle_context_pt context); +typedef celix_status_t (*destroy_function_pt)(void * handle, bundle_context_pt context); + +struct activator { + void * userData; + start_function_pt start; + stop_function_pt stop; + destroy_function_pt destroy; +}; + +celix_status_t framework_setBundleStateAndNotify(framework_pt framework, bundle_pt bundle, int state); +celix_status_t framework_markBundleResolved(framework_pt framework, module_pt module); + +celix_status_t framework_acquireBundleLock(framework_pt framework, bundle_pt bundle, int desiredStates); +bool framework_releaseBundleLock(framework_pt framework, bundle_pt bundle); + +bool framework_acquireGlobalLock(framework_pt framework); +celix_status_t framework_releaseGlobalLock(framework_pt framework); + +celix_status_t framework_acquireInstallLock(framework_pt framework, const char* location); +celix_status_t framework_releaseInstallLock(framework_pt framework, const char* location); + +long framework_getNextBundleId(framework_pt framework); + +celix_status_t fw_installBundle2(framework_pt framework, bundle_pt * bundle, long id, const char * location, const char *inputFile, bundle_archive_pt archive); + +celix_status_t fw_refreshBundles(framework_pt framework, bundle_pt bundles[], int size); +celix_status_t fw_refreshBundle(framework_pt framework, bundle_pt bundle); + +celix_status_t fw_populateDependentGraph(framework_pt framework, bundle_pt exporter, hash_map_pt *map); + +celix_status_t fw_fireBundleEvent(framework_pt framework, bundle_event_type_e, bundle_pt bundle); +celix_status_t fw_fireFrameworkEvent(framework_pt framework, framework_event_type_e eventType, bundle_pt bundle, celix_status_t errorCode); +static void *fw_eventDispatcher(void *fw); + +celix_status_t fw_invokeBundleListener(framework_pt framework, bundle_listener_pt listener, bundle_event_pt event, bundle_pt bundle); +celix_status_t fw_invokeFrameworkListener(framework_pt framework, framework_listener_pt listener, framework_event_pt event, bundle_pt bundle); + +static celix_status_t framework_loadBundleLibraries(framework_pt framework, bundle_pt bundle); +static celix_status_t framework_loadLibraries(framework_pt framework, const char* libraries, const char* activator, bundle_archive_pt archive, void **activatorHandle); +static celix_status_t framework_loadLibrary(framework_pt framework, const char* library, bundle_archive_pt archive, void **handle); + +static celix_status_t frameworkActivator_start(void * userData, bundle_context_pt context); +static celix_status_t frameworkActivator_stop(void * userData, bundle_context_pt context); +static celix_status_t frameworkActivator_destroy(void * userData, bundle_context_pt context); + + +struct fw_refreshHelper { + framework_pt framework; + bundle_pt bundle; + bundle_state_e oldState; +}; + +celix_status_t fw_refreshHelper_refreshOrRemove(struct fw_refreshHelper * refreshHelper); +celix_status_t fw_refreshHelper_restart(struct fw_refreshHelper * refreshHelper); +celix_status_t fw_refreshHelper_stop(struct fw_refreshHelper * refreshHelper); + +struct fw_serviceListener { + bundle_pt bundle; + service_listener_pt listener; + filter_pt filter; + array_list_pt retainedReferences; +}; + +typedef struct fw_serviceListener * fw_service_listener_pt; + +struct fw_bundleListener { + bundle_pt bundle; + bundle_listener_pt listener; +}; + +typedef struct fw_bundleListener * fw_bundle_listener_pt; + +struct fw_frameworkListener { + bundle_pt bundle; + framework_listener_pt listener; +}; + +typedef struct fw_frameworkListener * fw_framework_listener_pt; + +enum event_type { + FRAMEWORK_EVENT_TYPE, + BUNDLE_EVENT_TYPE, + EVENT_TYPE_SERVICE, +}; + +typedef enum event_type event_type_e; + +struct request { + event_type_e type; + array_list_pt listeners; + + int eventType; + long bundleId; + char* bundleSymbolicName; + celix_status_t errorCode; + char *error; + + char *filter; +}; + +typedef struct request *request_pt; + +framework_logger_pt logger; + +//TODO introduce a counter + mutex to control the freeing of the logger when mutiple threads are running a framework. +static celix_thread_once_t loggerInit = CELIX_THREAD_ONCE_INIT; +static void framework_loggerInit(void) { + logger = malloc(sizeof(*logger)); + logger->logFunction = frameworkLogger_log; +} + +/* Note: RTLD_NODELETE flag is needed in order to obtain a readable valgrind output. + * Valgrind output is written when the application terminates, so symbols resolving + * is impossible if dlopened libraries are unloaded before the application ends. + * RTLD_NODELETE closes the dynamic library but does not unload it from the memory space, + * so that symbols will be available until the application terminates. + * On the other hand, since the memory mapping is not destroyed after dlclose, calling again + * dlopen for the same library clashes with the previous mapping: this breaks the memory layout + * in case the user, for example, uninstall (dlclose) and install the bundle again (dlopen) + * So, RTLD_NODELETE should be used only for debugging purposes. + * Refer to dlopen manpage for additional details about libraries dynamic loading. + */ +#ifdef _WIN32 + #define handle_t HMODULE + #define fw_openLibrary(path) LoadLibrary(path) + #define fw_closeLibrary(handle) FreeLibrary(handle) + + #define fw_getSymbol(handle, name) GetProcAddress(handle, name) + + #define fw_getLastError() GetLastError() + + HMODULE fw_getCurrentModule() { + HMODULE hModule = NULL; + GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)fw_getCurrentModule, &hModule); + return hModule; + } +#else + #define handle_t void * + #if defined(DEBUG) && !defined(ANDROID) + #define fw_openLibrary(path) dlopen(path, RTLD_LAZY|RTLD_LOCAL|RTLD_NODELETE) + #else + #define fw_openLibrary(path) dlopen(path, RTLD_LAZY|RTLD_LOCAL) + #endif + #define fw_closeLibrary(handle) dlclose(handle) + #define fw_getSymbol(handle, name) dlsym(handle, name) + #define fw_getLastError() dlerror() +#endif + +celix_status_t framework_create(framework_pt *framework, properties_pt config) { + celix_status_t status = CELIX_SUCCESS; + + logger = hashMap_get(config, "logger"); + if (logger == NULL) { + celixThread_once(&loggerInit, framework_loggerInit); + } + + *framework = (framework_pt) malloc(sizeof(**framework)); + if (*framework != NULL) { + status = CELIX_DO_IF(status, celixThreadCondition_init(&(*framework)->condition, NULL)); + status = CELIX_DO_IF(status, celixThreadMutex_create(&(*framework)->mutex, NULL)); + status = CELIX_DO_IF(status, celixThreadMutex_create(&(*framework)->installedBundleMapLock, NULL)); + status = CELIX_DO_IF(status, celixThreadMutex_create(&(*framework)->bundleLock, NULL)); + status = CELIX_DO_IF(status, celixThreadMutex_create(&(*framework)->installRequestLock, NULL)); + status = CELIX_DO_IF(status, celixThreadMutex_create(&(*framework)->dispatcherLock, NULL)); + status = CELIX_DO_IF(status, celixThreadMutex_create(&(*framework)->bundleListenerLock, NULL)); + status = CELIX_DO_IF(status, celixThreadCondition_init(&(*framework)->dispatcher, NULL)); + if (status == CELIX_SUCCESS) { + (*framework)->bundle = NULL; + (*framework)->installedBundleMap = NULL; + (*framework)->registry = NULL; + (*framework)->interrupted = false; + (*framework)->shutdown = false; + (*framework)->globalLockWaitersList = NULL; + (*framework)->globalLockCount = 0; + (*framework)->globalLockThread = celix_thread_default; + (*framework)->nextBundleId = 1l; + (*framework)->cache = NULL; + (*framework)->installRequestMap = hashMap_create(utils_stringHash, utils_stringHash, utils_stringEquals, utils_stringEquals); + (*framework)->serviceListeners = NULL; + (*framework)->bundleListeners = NULL; + (*framework)->frameworkListeners = NULL; + (*framework)->requests = NULL; + (*framework)->configurationMap = config; + (*framework)->logger = logger; + + + status = CELIX_DO_IF(status, bundle_create(&(*framework)->bundle)); + status = CELIX_DO_IF(status, arrayList_create(&(*framework)->globalLockWaitersList)); + status = CELIX_DO_IF(status, bundle_setFramework((*framework)->bundle, (*framework))); + if (status == CELIX_SUCCESS) { + // + } else { + status = CELIX_FRAMEWORK_EXCEPTION; + fw_logCode((*framework)->logger, OSGI_FRAMEWORK_LOG_ERROR, status, "Could not create framework"); + } + } else { + status = CELIX_FRAMEWORK_EXCEPTION; + fw_logCode((*framework)->logger, OSGI_FRAMEWORK_LOG_ERROR, status, "Could not create framework"); + } + } else { + status = CELIX_FRAMEWORK_EXCEPTION; + fw_logCode(logger, OSGI_FRAMEWORK_LOG_ERROR, CELIX_ENOMEM, "Could not create framework"); + } + + return status; +} + +celix_status_t framework_destroy(framework_pt framework) { + celix_status_t status = CELIX_SUCCESS; + + celixThreadMutex_lock(&framework->installedBundleMapLock); + + if (framework->installedBundleMap != NULL) { + hash_map_iterator_pt iterator = hashMapIterator_create(framework->installedBundleMap); + while (hashMapIterator_hasNext(iterator)) { + hash_map_entry_pt entry = hashMapIterator_nextEntry(iterator); + bundle_pt bundle = (bundle_pt) hashMapEntry_getValue(entry); + char * key = hashMapEntry_getKey(entry); + bundle_archive_pt archive = NULL; + + bool systemBundle = false; + bundle_isSystemBundle(bundle, &systemBundle); + if (systemBundle) { + bundle_context_pt context = NULL; + bundle_getContext(framework->bundle, &context); + bundleContext_destroy(context); + } + + if (bundle_getArchive(bundle, &archive) == CELIX_SUCCESS) { + if (!systemBundle) { + bundle_revision_pt revision = NULL; + array_list_pt handles = NULL; + status = CELIX_DO_IF(status, bundleArchive_getCurrentRevision(archive, &revision)); + status = CELIX_DO_IF(status, bundleRevision_getHandles(revision, &handles)); + if (handles != NULL) { + for (int i = arrayList_size(handles) - 1; i >= 0; i--) { + void *handle = arrayList_get(handles, i); + fw_closeLibrary(handle); + } + } + } + + bundleArchive_destroy(archive); + } + bundle_destroy(bundle); + hashMapIterator_remove(iterator); + free(key); + } + hashMapIterator_destroy(iterator); + } + + celixThreadMutex_unlock(&framework->installedBundleMapLock); + + hashMap_destroy(framework->installRequestMap, false, false); + + serviceRegistry_destroy(framework->registry); + + arrayList_destroy(framework->globalLockWaitersList); + + if (framework->serviceListeners != NULL) { + arrayList_destroy(framework->serviceListeners); + } + if (framework->bundleListeners) { + arrayList_destroy(framework->bundleListeners); + } + if (framework->frameworkListeners) { + arrayList_destroy(framework->frameworkListeners); + } + + if(framework->requests){ + int i; + for (i = 0; i < arrayList_size(framework->requests); i++) { + request_pt request = arrayList_get(framework->requests, i); + free(request); + } + arrayList_destroy(framework->requests); + } + if(framework->installedBundleMap!=NULL){ + hashMap_destroy(framework->installedBundleMap, true, false); + } + + bundleCache_destroy(&framework->cache); + + celixThreadCondition_destroy(&framework->dispatcher); + celixThreadMutex_destroy(&framework->bundleListenerLock); + celixThreadMutex_destroy(&framework->dispatcherLock); + celixThreadMutex_destroy(&framework->installRequestLock); + celixThreadMutex_destroy(&framework->bundleLock); + celixThreadMutex_destroy(&framework->installedBundleMapLock); + celixThreadMutex_destroy(&framework->mutex); + celixThreadCondition_destroy(&framework->condition); + + logger = hashMap_get(framework->configurationMap, "logger"); + if (logger == NULL) { + free(framework->logger); + } + + properties_destroy(framework->configurationMap); + + free(framework); + + return status; +} + +celix_status_t fw_init(framework_pt framework) { + bundle_state_e state; + const char *location = NULL; + module_pt module = NULL; + linked_list_pt wires = NULL; + array_list_pt archives = NULL; + bundle_archive_pt archive = NULL; + + celix_status_t status = CELIX_SUCCESS; + status = CELIX_DO_IF(status, framework_acquireBundleLock(framework, framework->bundle, OSGI_FRAMEWORK_BUNDLE_INSTALLED|OSGI_FRAMEWORK_BUNDLE_RESOLVED|OSGI_FRAMEWORK_BUNDLE_STARTING|OSGI_FRAMEWORK_BUNDLE_ACTIVE)); + status = CELIX_DO_IF(status, arrayList_create(&framework->serviceListeners)); + status = CELIX_DO_IF(status, arrayList_create(&framework->bundleListeners)); + status = CELIX_DO_IF(status, arrayList_create(&framework->frameworkListeners)); + status = CELIX_DO_IF(status, arrayList_create(&framework->requests)); + status = CELIX_DO_IF(status, celixThread_create(&framework->dispatcherThread, NULL, fw_eventDispatcher, framework)); + status = CELIX_DO_IF(status, bundle_getState(framework->bundle, &state)); + if (status == CELIX_SUCCESS) { + if ((state == OSGI_FRAMEWORK_BUNDLE_INSTALLED) || (state == OSGI_FRAMEWORK_BUNDLE_RESOLVED)) { + bundle_state_e state; + status = CELIX_DO_IF(status, bundleCache_create(framework->configurationMap,&framework->cache)); + status = CELIX_DO_IF(status, bundle_getState(framework->bundle, &state)); + if (status == CELIX_SUCCESS) { + if (state == OSGI_FRAMEWORK_BUNDLE_INSTALLED) { + const char *clean = properties_get(framework->configurationMap, OSGI_FRAMEWORK_FRAMEWORK_STORAGE_CLEAN); + if (clean != NULL && (strcmp(clean, OSGI_FRAMEWORK_FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT) == 0)) { + bundleCache_delete(framework->cache); + } + } + } + } + } + + if (status == CELIX_SUCCESS) { + /*create and store framework uuid*/ + char uuid[37]; + + uuid_t uid; + uuid_generate(uid); + uuid_unparse(uid, uuid); + + properties_set(framework->configurationMap, (char*) OSGI_FRAMEWORK_FRAMEWORK_UUID, uuid); + + framework->installedBundleMap = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL); + } + + status = CELIX_DO_IF(status, bundle_getArchive(framework->bundle, &archive)); + status = CELIX_DO_IF(status, bundleArchive_getLocation(archive, &location)); + if (status == CELIX_SUCCESS) { + hashMap_put(framework->installedBundleMap, strdup(location), framework->bundle); + } + status = CELIX_DO_IF(status, bundle_getCurrentModule(framework->bundle, &module)); + if (status == CELIX_SUCCESS) { + wires = resolver_resolve(module); + if (wires != NULL) { + framework_markResolvedModules(framework, wires); + } else { + status = CELIX_BUNDLE_EXCEPTION; + fw_logCode(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, status, "Unresolved constraints in System Bundle"); + } + } + + status = CELIX_DO_IF(status, bundleCache_getArchives(framework->cache, &archives)); + if (status == CELIX_SUCCESS) { + unsigned int arcIdx; + for (arcIdx = 0; arcIdx < arrayList_size(archives); arcIdx++) { + bundle_archive_pt archive1 = (bundle_archive_pt) arrayList_get(archives, arcIdx); + long id; + bundle_state_e bundleState; + bundleArchive_getId(archive1, &id); + framework->nextBundleId = framework->nextBundleId > id + 1 ? framework->nextBundleId : id + 1; + + bundleArchive_getPersistentState(archive1, &bundleState); + if (bundleState == OSGI_FRAMEWORK_BUNDLE_UNINSTALLED) { + bundleArchive_closeAndDelete(archive1); + } else { + bundle_pt bundle = NULL; + const char *location1 = NULL; + status = bundleArchive_getLocation(archive1, &location1); + fw_installBundle2(framework, &bundle, id, location1, NULL, archive1); + } + } + arrayList_destroy(archives); + } + + status = CELIX_DO_IF(status, serviceRegistry_create(framework, fw_serviceChanged, &framework->registry)); + status = CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, framework->bundle, OSGI_FRAMEWORK_BUNDLE_STARTING)); + status = CELIX_DO_IF(status, celixThreadCondition_init(&framework->shutdownGate, NULL)); + + bundle_context_pt context = NULL; + status = CELIX_DO_IF(status, bundleContext_create(framework, framework->logger, framework->bundle, &context)); + status = CELIX_DO_IF(status, bundle_setContext(framework->bundle, context)); + if (status == CELIX_SUCCESS) { + activator_pt activator = NULL; + activator = (activator_pt) calloc(1,(sizeof(*activator))); + if (activator != NULL) { + bundle_context_pt context = NULL; + void * userData = NULL; + + //create_function_pt create = NULL; + start_function_pt start = (start_function_pt) frameworkActivator_start; + stop_function_pt stop = (stop_function_pt) frameworkActivator_stop; + destroy_function_pt destroy = (destroy_function_pt) frameworkActivator_destroy; + + activator->start = start; + activator->stop = stop; + activator->destroy = destroy; + status = CELIX_DO_IF(status, bundle_setActivator(framework->bundle, activator)); + status = CELIX_DO_IF(status, bundle_getContext(framework->bundle, &context)); + + if (status == CELIX_SUCCESS) { + /* This code part is in principle dead, but in future it may do something. + * That's why it's outcommented and not deleted + if (create != NULL) { + create(context, &userData); + } + */ + activator->userData = userData; + + if (start != NULL) { + start(userData, context); + } + } + else{ + free(activator); + } + } else { + status = CELIX_ENOMEM; + } + } + + if (status != CELIX_SUCCESS) { + fw_logCode(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, status, "Could not init framework"); + } + + framework_releaseBundleLock(framework, framework->bundle); + + return status; +} + +celix_status_t framework_start(framework_pt framework) { + celix_status_t status = CELIX_SUCCESS; + bundle_state_e state = OSGI_FRAMEWORK_BUNDLE_UNKNOWN; + + status = CELIX_DO_IF(status, framework_acquireBundleLock(framework, framework->bundle, OSGI_FRAMEWORK_BUNDLE_INSTALLED|OSGI_FRAMEWORK_BUNDLE_RESOLVED|OSGI_FRAMEWORK_BUNDLE_STARTING|OSGI_FRAMEWORK_BUNDLE_ACTIVE)); + status = CELIX_DO_IF(status, bundle_getState(framework->bundle, &state)); + if (status == CELIX_SUCCESS) { + if ((state == OSGI_FRAMEWORK_BUNDLE_INSTALLED) || (state == OSGI_FRAMEWORK_BUNDLE_RESOLVED)) { + status = CELIX_DO_IF(status, fw_init(framework)); + } + } + + status = CELIX_DO_IF(status, bundle_getState(framework->bundle, &state)); + if (status == CELIX_SUCCESS) { + if (state == OSGI_FRAMEWORK_BUNDLE_STARTING) { + status = CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, framework->bundle, OSGI_FRAMEWORK_BUNDLE_ACTIVE)); + } + + framework_releaseBundleLock(framework, framework->bundle); + } + + status = CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_STARTED, framework->bundle)); + status = CELIX_DO_IF(status, fw_fireFrameworkEvent(framework, OSGI_FRAMEWORK_EVENT_STARTED, framework->bundle, 0)); + + if (status != CELIX_SUCCESS) { + status = CELIX_BUNDLE_EXCEPTION; + fw_logCode(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, status, "Could not start framework"); + fw_fireFrameworkEvent(framework, OSGI_FRAMEWORK_EVENT_ERROR, framework->bundle, status); + } + + return status; +} + +void framework_stop(framework_pt framework) { + fw_stopBundle(framework, framework->bundle, true); +} + +celix_status_t fw_getProperty(framework_pt framework, const char* name, const char* defaultValue, const char** value) { + celix_status_t status = CELIX_SUCCESS; + + if (framework == NULL || name == NULL || *value != NULL) { + status = CELIX_ILLEGAL_ARGUMENT; + } else { + if (framework->configurationMap != NULL) { + *value = properties_get(framework->configurationMap, name); + } + if (*value == NULL) { + *value = getenv(name); + } + if (*value == NULL) { + *value = defaultValue; + } + } + + return status; +} + +celix_status_t fw_installBundle(framework_pt framework, bundle_pt * bundle, const char * location, const char *inputFile) { + return fw_installBundle2(framework, bundle, -1, location, inputFile, NULL); +} + +celix_status_t fw_installBundle2(framework_pt framework, bundle_pt * bundle, long id, const char * location, const char *inputFile, bundle_archive_pt archive) { + celix_status_t status = CELIX_SUCCESS; +// bundle_archive_pt bundle_archive = NULL; + bundle_state_e state = OSGI_FRAMEWORK_BUNDLE_UNKNOWN; + bool locked; + + status = CELIX_DO_IF(status, framework_acquireInstallLock(framework, location)); + status = CELIX_DO_IF(status, bundle_getState(framework->bundle, &state)); + if (status == CELIX_SUCCESS) { + if (state == OSGI_FRAMEWORK_BUNDLE_STOPPING || state == OSGI_FRAMEWORK_BUNDLE_UNINSTALLED) { + fw_log(framework->logger, OSGI_FRAMEWORK_LOG_INFO, "The framework is being shutdown"); + status = CELIX_DO_IF(status, framework_releaseInstallLock(framework, location)); + status = CELIX_FRAMEWORK_SHUTDOWN; + } + } + + if (status == CELIX_SUCCESS) { + *bundle = framework_getBundle(framework, location); + if (*bundle != NULL) { + framework_releaseInstallLock(framework, location); + return CELIX_SUCCESS; + } + + if (archive == NULL) { + id = framework_getNextBundleId(framework); + + status = CELIX_DO_IF(status, bundleCache_createArchive(framework->cache, id, location, inputFile, &archive)); + + if (status != CELIX_SUCCESS) { + bundleArchive_destroy(archive); + } + } else { + // purge revision + // multiple revisions not yet implemented + } + + if (status == CELIX_SUCCESS) { + locked = framework_acquireGlobalLock(framework); + if (!locked) { + status = CELIX_BUNDLE_EXCEPTION; + } else { + status = CELIX_DO_IF(status, bundle_createFromArchive(bundle, framework, archive)); + + framework_releaseGlobalLock(framework); + if (status == CELIX_SUCCESS) { + celixThreadMutex_lock(&framework->installedBundleMapLock); + hashMap_put(framework->installedBundleMap, strdup(location), *bundle); + celixThreadMutex_unlock(&framework->installedBundleMapLock); + + } else { + status = CELIX_BUNDLE_EXCEPTION; + status = CELIX_DO_IF(status, bundleArchive_closeAndDelete(archive)); + } + } + } + } + + framework_releaseInstallLock(framework, location); + + if (status != CELIX_SUCCESS) { + fw_logCode(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, status, "Could not install bundle"); + } else { + status = CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_INSTALLED, *bundle)); + } + + return status; +} + +celix_status_t framework_getBundleEntry(framework_pt framework, bundle_pt bundle, const char* name, char** entry) { + celix_status_t status = CELIX_SUCCESS; + + bundle_revision_pt revision; + bundle_archive_pt archive = NULL; + const char *root; + + status = CELIX_DO_IF(status, bundle_getArchive(bundle, &archive)); + status = CELIX_DO_IF(status, bundleArchive_getCurrentRevision(archive, &revision)); + status = CELIX_DO_IF(status, bundleRevision_getRoot(revision, &root)); + if (status == CELIX_SUCCESS) { + char e[strlen(name) + strlen(root) + 2]; + strcpy(e, root); + if ((strlen(name) > 0) && (name[0] == '/')) { + strcat(e, name); + } else { + strcat(e, "/"); + strcat(e, name); + } + + if (access(e, F_OK) == 0) { + (*entry) = strndup(e, 1024*10); + } else { + (*entry) = NULL; + } + } + + return status; +} + +celix_status_t fw_startBundle(framework_pt framework, bundle_pt bundle, int options) { + celix_status_t status = CELIX_SUCCESS; + + linked_list_pt wires = NULL; + bundle_context_pt context = NULL; + bundle_state_e state; + module_pt module = NULL; + activator_pt activator = NULL; + char *error = NULL; + const char *name = NULL; + + status = CELIX_DO_IF(status, framework_acquireBundleLock(framework, bundle, OSGI_FRAMEWORK_BUNDLE_INSTALLED|OSGI_FRAMEWORK_BUNDLE_RESOLVED|OSGI_FRAMEWORK_BUNDLE_STARTING|OSGI_FRAMEWORK_BUNDLE_ACTIVE)); + status = CELIX_DO_IF(status, bundle_getState(bundle, &state)); + + if (status == CELIX_SUCCESS) { + switch (state) { + case OSGI_FRAMEWORK_BUNDLE_UNKNOWN: + error = "state is unknown"; + status = CELIX_ILLEGAL_STATE; + break; + case OSGI_FRAMEWORK_BUNDLE_UNINSTALLED: + error = "bundle is uninstalled"; + status = CELIX_ILLEGAL_STATE; + break; + case OSGI_FRAMEWORK_BUNDLE_STARTING: + error = "bundle is starting"; + status = CELIX_BUNDLE_EXCEPTION; + break; + case OSGI_FRAMEWORK_BUNDLE_STOPPING: + error = "bundle is stopping"; + status = CELIX_BUNDLE_EXCEPTION; + break; + case OSGI_FRAMEWORK_BUNDLE_ACTIVE: + break; + case OSGI_FRAMEWORK_BUNDLE_INSTALLED: + bundle_getCurrentModule(bundle, &module); + module_getSymbolicName(module, &name); + if (!module_isResolved(module)) { + wires = resolver_resolve(module); + if (wires == NULL) { + framework_releaseBundleLock(framework, bundle); + return CELIX_BUNDLE_EXCEPTION; + } + framework_markResolvedModules(framework, wires); + + } + /* no break */ + case OSGI_FRAMEWORK_BUNDLE_RESOLVED: + module = NULL; + name = NULL; + bundle_getCurrentModule(bundle, &module); + module_getSymbolicName(module, &name); + status = CELIX_DO_IF(status, bundleContext_create(framework, framework->logger, bundle, &context)); + status = CELIX_DO_IF(status, bundle_setContext(bundle, context)); + + if (status == CELIX_SUCCESS) { + activator = (activator_pt) calloc(1,(sizeof(*activator))); + if (activator == NULL) { + status = CELIX_ENOMEM; + } else { + void * userData = NULL; + bundle_context_pt context; + create_function_pt create = (create_function_pt) fw_getSymbol((handle_t) bundle_getHandle(bundle), OSGI_FRAMEWORK_BUNDLE_ACTIVATOR_CREATE); + start_function_pt start = (start_function_pt) fw_getSymbol((handle_t) bundle_getHandle(bundle), OSGI_FRAMEWORK_BUNDLE_ACTIVATOR_START); + stop_function_pt stop = (stop_function_pt) fw_getSymbol((handle_t) bundle_getHandle(bundle), OSGI_FRAMEWORK_BUNDLE_ACTIVATOR_STOP); + destroy_function_pt destroy = (destroy_function_pt) fw_getSymbol((handle_t) bundle_getHandle(bundle), OSGI_FRAMEWORK_BUNDLE_ACTIVATOR_DESTROY); + + activator->start = start; + activator->stop = stop; + activator->destroy = destroy; + status = CELIX_DO_IF(status, bundle_setActivator(bundle, activator)); + + status = CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, bundle, OSGI_FRAMEWORK_BUNDLE_STARTING)); + status = CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_STARTING, bundle)); + + status = CELIX_DO_IF(status, bundle_getContext(bundle, &context)); + + if (status == CELIX_SUCCESS) { + if (create != NULL) { + status = CELIX_DO_IF(status, create(context, &userData)); + if (status == CELIX_SUCCESS) { + activator->userData = userData; + } + } + } + if (status == CELIX_SUCCESS) { + if (start != NULL) { + status = CELIX_DO_IF(status, start(userData, context)); + } + } + + status = CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, bundle, OSGI_FRAMEWORK_BUNDLE_ACTIVE)); + status = CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_STARTED, bundle)); + } + } + + break; + } + } + + framework_releaseBundleLock(framework, bundle); + + if (status != CELIX_SUCCESS) { + module_pt module = NULL; + const char *symbolicName = NULL; + long id = 0; + bundle_getCurrentModule(bundle, &module); + module_getSymbolicName(module, &symbolicName); + bundle_getBundleId(bundle, &id); + if (error != NULL) { + fw_logCode(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, status, "Could not start bundle: %s [%ld]; cause: %s", symbolicName, id, error); + } else { + fw_logCode(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, status, "Could not start bundle: %s [%ld]", symbolicName, id); + } + if(activator!=NULL){ + free(activator); + } + } + + return status; +} + +celix_status_t framework_updateBundle(framework_pt framework, bundle_pt bundle, const char *inputFile) { + celix_status_t status = CELIX_SUCCESS; + bundle_state_e oldState; + const char *location; + bundle_archive_pt archive = NULL; + char *error = NULL; + + status = CELIX_DO_IF(status, framework_acquireBundleLock(framework, bundle, OSGI_FRAMEWORK_BUNDLE_INSTALLED|OSGI_FRAMEWORK_BUNDLE_RESOLVED|OSGI_FRAMEWORK_BUNDLE_ACTIVE)); + status = CELIX_DO_IF(status, bundle_getState(bundle, &oldState)); + if (status == CELIX_SUCCESS) { + if (oldState == OSGI_FRAMEWORK_BUNDLE_ACTIVE) { + fw_stopBundle(framework, bundle, false); + } + } + status = CELIX_DO_IF(status, bundle_getArchive(bundle, &archive)); + status = CELIX_DO_IF(status, bundleArchive_getLocation(archive, &location)); + + if (status == CELIX_SUCCESS) { + bool locked = framework_acquireGlobalLock(framework); + if (!locked) { + status = CELIX_BUNDLE_EXCEPTION; + error = "Unable to acquire the global lock to update the bundle"; + } + } + + status = CELIX_DO_IF(status, bundle_revise(bundle, location, inputFile)); + status = CELIX_DO_IF(status, framework_releaseGlobalLock(framework)); + + status = CELIX_DO_IF(status, bundleArchive_setLastModified(archive, time(NULL))); + status = CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, bundle, OSGI_FRAMEWORK_BUNDLE_INSTALLED)); + + bundle_revision_pt revision = NULL; + array_list_pt handles = NULL; + status = CELIX_DO_IF(status, bundleArchive_getCurrentRevision(archive, &revision)); + status = CELIX_DO_IF(status, bundleRevision_getHandles(revision, &handles)); + if (handles != NULL) { + int i; + for (i = arrayList_size(handles) - 1; i >= 0; i--) { + void* handle = arrayList_get(handles, i); + fw_closeLibrary(handle); + } + } + + + status = CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_UNRESOLVED, bundle)); + status = CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_UPDATED, bundle)); + + // Refresh packages? + + if (status == CELIX_SUCCESS) { + if (oldState == OSGI_FRAMEWORK_BUNDLE_ACTIVE) { + status = CELIX_DO_IF(status, fw_startBundle(framework, bundle, 1)); + } + } + + framework_releaseBundleLock(framework, bundle); + + if (status != CELIX_SUCCESS) { + module_pt module = NULL; + const char *symbolicName = NULL; + long id = 0; + bundle_getCurrentModule(bundle, &module); + module_getSymbolicName(module, &symbolicName); + bundle_getBundleId(bundle, &id); + if (error != NULL) { + fw_logCode(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, status, "Cannot update bundle: %s [%ld]; cause: %s", symbolicName, id, error); + } else { + fw_logCode(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, status, "Cannot update bundle: %s [%ld]", symbolicName, id); + } + } + + return status; +} + +celix_status_t fw_stopBundle(framework_pt framework, bundle_pt bundle, bool record) { + celix_status_t status = CELIX_SUCCESS; + bundle_state_e state; + activator_pt activator = NULL; + bundle_context_pt context = NULL; + bool wasActive = false; + long id = 0; + char *error = NULL; + + status = CELIX_DO_IF(status, framework_acquireBundleLock(framework, bundle, OSGI_FRAMEWORK_BUNDLE_INSTALLED|OSGI_FRAMEWORK_BUNDLE_RESOLVED|OSGI_FRAMEWORK_BUNDLE_STARTING|OSGI_FRAMEWORK_BUNDLE_ACTIVE)); + + if (record) { + status = CELIX_DO_IF(status, bundle_setPersistentStateInactive(bundle)); + } + + status = CELIX_DO_IF(status, bundle_getState(bundle, &state)); + if (status == CELIX_SUCCESS) { + switch (state) { + case OSGI_FRAMEWORK_BUNDLE_UNKNOWN: + status = CELIX_ILLEGAL_STATE; + error = "state is unknown"; + break; + case OSGI_FRAMEWORK_BUNDLE_UNINSTALLED: + status = CELIX_ILLEGAL_STATE; + error = "bundle is uninstalled"; + break; + case OSGI_FRAMEWORK_BUNDLE_STARTING: + status = CELIX_BUNDLE_EXCEPTION; + error = "bundle is starting"; + break; + case OSGI_FRAMEWORK_BUNDLE_STOPPING: + status = CELIX_BUNDLE_EXCEPTION; + error = "bundle is stopping"; + break; + case OSGI_FRAMEWORK_BUNDLE_INSTALLED: + case OSGI_FRAMEWORK_BUNDLE_RESOLVED: + break; + case OSGI_FRAMEWORK_BUNDLE_ACTIVE: + wasActive = true; + break; + } + } + + + status = CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, bundle, OSGI_FRAMEWORK_BUNDLE_STOPPING)); + status = CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_STOPPING, bundle)); + status = CELIX_DO_IF(status, bundle_getBundleId(bundle, &id)); + if (status == CELIX_SUCCESS) { + if (wasActive || (id == 0)) { + activator = bundle_getActivator(bundle); + + status = CELIX_DO_IF(status, bundle_getContext(bundle, &context)); + if (status == CELIX_SUCCESS) { + if (activator->stop != NULL) { + status = CELIX_DO_IF(status, activator->stop(activator->userData, context)); + } + } + if (status == CELIX_SUCCESS) { + if (activator->destroy != NULL) { + status = CELIX_DO_IF(status, activator->destroy(activator->userData, context)); + } + } + + if (id != 0) { + status = CELIX_DO_IF(status, serviceRegistry_clearServiceRegistrations(framework->registry, bundle)); + if (status == CELIX_SUCCESS) { + module_pt module = NULL; + const char *symbolicName = NULL; + long id = 0; + bundle_getCurrentModule(bundle, &module); + module_getSymbolicName(module, &symbolicName); + bundle_getBundleId(bundle, &id); + + serviceRegistry_clearReferencesFor(framework->registry, bundle); + } + // #TODO remove listeners for bundle + + if (context != NULL) { + status = CELIX_DO_IF(status, bundleContext_destroy(context)); + status = CELIX_DO_IF(status, bundle_setContext(bundle, NULL)); + } + + status = CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, bundle, OSGI_FRAMEWORK_BUNDLE_RESOLVED)); + } + } + + if (activator != NULL) { + bundle_setActivator(bundle, NULL); + free(activator); + } + } + + framework_releaseBundleLock(framework, bundle); + + if (status != CELIX_SUCCESS) { + module_pt module = NULL; + const char *symbolicName = NULL; + long id = 0; + bundle_getCurrentModule(bundle, &module); + module_getSymbolicName(module, &symbolicName); + bundle_getBundleId(bundle, &id); + if (error != NULL) { + fw_logCode(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, status, "Cannot stop bundle: %s [%ld]; cause: %s", symbolicName, id, error); + } else { + fw_logCode(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, status, "Cannot stop bundle: %s [%ld]", symbolicName, id); + } + } else { + fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_STOPPED, bundle); + } + + return status; +} + +celix_status_t fw_uninstallBundle(framework_pt framework, bundle_pt bundle) { + celix_status_t status = CELIX_SUCCESS; + bool locked; + bundle_archive_pt archive = NULL; + const char * location = NULL; + bundle_pt target = NULL; + char *error = NULL; + + status = CELIX_DO_IF(status, framework_acquireBundleLock(framework, bundle, OSGI_FRAMEWORK_BUNDLE_INSTALLED|OSGI_FRAMEWORK_BUNDLE_RESOLVED|OSGI_FRAMEWORK_BUNDLE_STARTING|OSGI_FRAMEWORK_BUNDLE_ACTIVE|OSGI_FRAMEWORK_BUNDLE_STOPPING)); + status = CELIX_DO_IF(status, fw_stopBundle(framework, bundle, true)); + if (status == CELIX_SUCCESS) { + locked = framework_acquireGlobalLock(framework); + if (!locked) { + status = CELIX_ILLEGAL_STATE; + error = "Unable to acquire the global lock to uninstall the bundle"; + } + } + + status = CELIX_DO_IF(status, bundle_getArchive(bundle, &archive)); + status = CELIX_DO_IF(status, bundleArchive_getLocation(archive, &location)); + if (status == CELIX_SUCCESS) { + + celixThreadMutex_lock(&framework->installedBundleMapLock); + + hash_map_entry_pt entry = hashMap_getEntry(framework->installedBundleMap, location); + char* entryLocation = hashMapEntry_getKey(entry); + + target = (bundle_pt) hashMap_remove(framework->installedBundleMap, location); + + free(entryLocation); + if (target != NULL) { + status = CELIX_DO_IF(status, bundle_setPersistentStateUninstalled(target)); + // fw_rememberUninstalledBundle(framework, target); + } + celixThreadMutex_unlock(&framework->installedBundleMapLock); + + } + + framework_releaseGlobalLock(framework); + + if (status == CELIX_SUCCESS) { + if (target == NULL) { + fw_log(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, "Could not remove bundle from installed map"); + } + } + + status = CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, bundle, OSGI_FRAMEWORK_BUNDLE_INSTALLED)); + + // TODO Unload all libraries for transition to unresolved + bundle_revision_pt revision = NULL; + array_list_pt handles = NULL; + status = CELIX_DO_IF(status, bundleArchive_getCurrentRevision(archive, &revision)); + status = CELIX_DO_IF(status, bundleRevision_getHandles(revision, &handles)); + if(handles != NULL){ + for (int i = arrayList_size(handles) - 1; i >= 0; i--) { + void *handle = arrayList_get(handles, i); + fw_closeLibrary(handle); + } + } + + status = CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_UNRESOLVED, bundle)); + + status = CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, bundle, OSGI_FRAMEWORK_BUNDLE_UNINSTALLED)); + status = CELIX_DO_IF(status, bundleArchive_setLastModified(archive, time(NULL))); + + framework_releaseBundleLock(framework, bundle); + + status = CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_UNINSTALLED, bundle)); + + if (status == CELIX_SUCCESS) { + locked = framework_acquireGlobalLock(framework); + if (locked) { + bundle_pt bundles[] = { bundle }; + celix_status_t refreshStatus = fw_refreshBundles(framework, bundles, 1); + if (refreshStatus != CELIX_SUCCESS) { + printf("Could not refresh bundle"); + } else { + bundleArchive_destroy(archive); + status = CELIX_DO_IF(status, bundle_destroy(bundle)); + } + + status = CELIX_DO_IF(status, framework_releaseGlobalLock(framework)); + } + } + + + if (status != CELIX_SUCCESS) { +// module_pt module = NULL; +// char *symbolicName = NULL; +// long id = 0; +// bundle_getCurrentModule(bundle, &module); +// module_getSymbolicName(module, &symbolicName); +// bundle_getBundleId(bundle, &id); + + framework_logIfError(framework->logger, status, error, "Cannot uninstall bundle"); + } + + return status; +} + +celix_status_t fw_refreshBundles(framework_pt framework, bundle_pt bundles[], int size) { + celix_status_t status = CELIX_SUCCESS; + + bool locked = framework_acquireGlobalLock(framework); + if (!locked) { + framework_releaseGlobalLock(framework); + status = CELIX_ILLEGAL_STATE; + } else { + hash_map_values_pt values; + bundle_pt *newTargets; + unsigned int nrofvalues; + bool restart = false; + hash_map_pt map = hashMap_create(NULL, NULL, NULL, NULL); + int targetIdx = 0; + for (targetIdx = 0; targetIdx < size; targetIdx++) { + bundle_pt bundle = bundles[targetIdx]; + hashMap_put(map, bundle, bundle); + fw_populateDependentGraph(framework, bundle, &map); + } + values = hashMapValues_create(map); + hashMapValues_toArray(values, (void ***) &newTargets, &nrofvalues); + hashMapValues_destroy(values); + + hashMap_destroy(map, false, false); + + if (newTargets != NULL) { + int i = 0; + struct fw_refreshHelper * helpers; + for (i = 0; i < nrofvalues && !restart; i++) { + bundle_pt bundle = (bundle_pt) newTargets[i]; + if (framework->bundle == bundle) { + restart = true; + } + } + + helpers = (struct fw_refreshHelper * )malloc(nrofvalues * sizeof(struct fw_refreshHelper)); + for (i = 0; i < nrofvalues && !restart; i++) { + bundle_pt bundle = (bundle_pt) newTargets[i]; + helpers[i].framework = framework; + helpers[i].bundle = bundle; + helpers[i].oldState = OSGI_FRAMEWORK_BUNDLE_INSTALLED; + } + + for (i = 0; i < nrofvalues; i++) { + struct fw_refreshHelper helper = helpers[i]; + fw_refreshHelper_stop(&helper); + fw_refreshHelper_refreshOrRemove(&helper); + } + + for (i = 0; i < nrofvalues; i++) { + struct fw_refreshHelper helper = helpers[i]; + fw_refreshHelper_restart(&helper); + } + + if (restart) { + bundle_update(framework->bundle, NULL); + } + free(helpers); + free(newTargets); + } + + framework_releaseGlobalLock(framework); + } + + framework_logIfError(framework->logger, status, NULL, "Cannot refresh bundles"); + + return status; +} + +celix_status_t fw_refreshBundle(framework_pt framework, bundle_pt bundle) { + celix_status_t status = CELIX_SUCCESS; + bundle_state_e state; + + status = framework_acquireBundleLock(framework, bundle, OSGI_FRAMEWORK_BUNDLE_INSTALLED | OSGI_FRAMEWORK_BUNDLE_RESOLVED); + if (status != CELIX_SUCCESS) { + printf("Cannot refresh bundle"); + framework_releaseBundleLock(framework, bundle); + } else { + bool fire; + bundle_getState(bundle, &state); + fire = (state != OSGI_FRAMEWORK_BUNDLE_INSTALLED); + bundle_refresh(bundle); + + if (fire) { + framework_setBundleStateAndNotify(framework, bundle, OSGI_FRAMEWORK_BUNDLE_INSTALLED); + fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_UNRESOLVED, bundle); + } + + framework_releaseBundleLock(framework, bundle); + } + + framework_logIfError(framework->logger, status, NULL, "Cannot refresh bundle"); + + return status; +} + +celix_status_t fw_refreshHelper_stop(struct fw_refreshHelper * refreshHelper) { + bundle_state_e state; + bundle_getState(refreshHelper->bundle, &state); + if (state == OSGI_FRAMEWORK_BUNDLE_ACTIVE) { + refreshHelper->oldState = OSGI_FRAMEWORK_BUNDLE_ACTIVE; + fw_stopBundle(refreshHelper->framework, refreshHelper->bundle, false); + } + + return CELIX_SUCCESS; +} + +celix_status_t fw_refreshHelper_refreshOrRemove(struct fw_refreshHelper * refreshHelper) { + bundle_state_e state; + bundle_getState(refreshHelper->bundle, &state); + if (state == OSGI_FRAMEWORK_BUNDLE_UNINSTALLED) { + bundle_closeAndDelete(refreshHelper->bundle); + refreshHelper->bundle = NULL; + } else { + fw_refreshBundle(refreshHelper->framework, refreshHelper->bundle); + } + return CELIX_SUCCESS; +} + +celix_status_t fw_refreshHelper_restart(struct fw_refreshHelper * refreshHelper) { + if ((refreshHelper->bundle != NULL) && (refreshHelper->oldState == OSGI_FRAMEWORK_BUNDLE_ACTIVE)) { + fw_startBundle(refreshHelper->framework, refreshHelper->bundle, 0); + } + return CELIX_SUCCESS; +} + +celix_status_t fw_getDependentBundles(framework_pt framework, bundle_pt exporter, array_list_pt *list) { + celix_status_t status = CELIX_SUCCESS; + + if (*list != NULL || exporter == NULL || framework == NULL) { + return CELIX_ILLEGAL_ARGUMENT; + } + + array_list_pt modules; + unsigned int modIdx = 0; + arrayList_create(list); + + modules = bundle_getModules(exporter); + for (modIdx = 0; modIdx < arrayList_size(modules); modIdx++) { + module_pt module = (module_pt) arrayList_get(modules, modIdx); + array_list_pt dependents = module_getDependents(module); + if(dependents!=NULL){ + unsigned int depIdx = 0; + for (depIdx = 0; depIdx < arrayList_size(dependents); depIdx++) { + module_pt dependent = (module_pt) arrayList_get(dependents, depIdx); + arrayList_add(*list, module_getBundle(dependent)); + } + arrayList_destroy(dependents); + } + } + + framework_logIfError(framework->logger, status, NULL, "Cannot get dependent bundles"); + + return status; +} + +celix_status_t fw_populateDependentGraph(framework_pt framework, bundle_pt exporter, hash_map_pt *map) { + celix_status_t status = CELIX_SUCCESS; + + if(framework == NULL || exporter == NULL){ + return CELIX_ILLEGAL_ARGUMENT; + } + + array_list_pt dependents = NULL; + if ((status = fw_getDependentBundles(framework, exporter, &dependents)) == CELIX_SUCCESS) { + if(dependents!=NULL){ + unsigned int depIdx = 0; + for (depIdx = 0; depIdx < arrayList_size(dependents); depIdx++) { + if (!hashMap_containsKey(*map, arrayList_get(dependents, depIdx))) { + hashMap_put(*map, arrayList_get(dependents, depIdx), arrayList_get(dependents, depIdx)); + fw_populateDependentGraph(framework, (bundle_pt) arrayList_get(dependents, depIdx), map); + } + } + arrayList_destroy(dependents); + } + } + + framework_logIfError(framework->logger, status, NULL, "Cannot populate dependent graph"); + + return status; +} + +celix_status_t fw_registerService(framework_pt framework, service_registration_pt *registration, bundle_pt bundle, const char* serviceName, const void* svcObj, properties_pt properties) { + celix_status_t status = CELIX_SUCCESS; + char *error = NULL; + if (serviceName == NULL || svcObj == NULL) { + status = CELIX_ILLEGAL_ARGUMENT; + error = "ServiceName and SvcObj cannot be null"; + } + + status = CELIX_DO_IF(status, framework_acquireBundleLock(framework, bundle, OSGI_FRAMEWORK_BUNDLE_STARTING|OSGI_FRAMEWORK_BUNDLE_ACTIVE)); + status = CELIX_DO_IF(status, serviceRegistry_registerService(framework->registry, bundle, serviceName, svcObj, properties, registration)); + bool res = framework_releaseBundleLock(framework, bundle); + if (!res) { + status = CELIX_ILLEGAL_STATE; + error = "Could not release bundle lock"; + } + + if (status == CELIX_SUCCESS) { + // If this is a listener hook, invoke the callback with all current listeners + if (strcmp(serviceName, OSGI_FRAMEWORK_LISTENER_HOOK_SERVICE_NAME) == 0) { + unsigned int i; + array_list_pt infos = NULL; + service_reference_pt ref = NULL; + listener_hook_service_pt hook = NULL; + + status = CELIX_DO_IF(status, arrayList_create(&infos)); + + if (status == CELIX_SUCCESS) { + celix_status_t subs = CELIX_SUCCESS; + + for (i = 0; i < arrayList_size(framework->serviceListeners); i++) { + fw_service_listener_pt listener =(fw_service_listener_pt) arrayList_get(framework->serviceListeners, i); + bundle_context_pt context = NULL; + listener_hook_info_pt info = NULL; + bundle_context_pt lContext = NULL; + + subs = CELIX_DO_IF(subs, bundle_getContext(bundle, &context)); + if (subs == CELIX_SUCCESS) { + info = (listener_hook_info_pt) malloc(sizeof(*info)); + if (info == NULL) { + subs = CELIX_ENOMEM; + } + } + + subs = CELIX_DO_IF(subs, bundle_getContext(listener->bundle, &lContext)); + if (subs == CELIX_SUCCESS) { + info->context = lContext; + info->removed = false; + } + subs = CELIX_DO_IF(subs, filter_getString(listener->filter, (const char**)&info->filter)); + + if (subs == CELIX_SUCCESS) { + arrayList_add(infos, info); + } + else{ + fw_logCode(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, status, "Could not pass all listeners to the hook: %s", serviceName); + free(info); + } + } + + status = CELIX_DO_IF(status, serviceRegistry_getServiceReference(framework->registry, framework->bundle, + *registration, &ref)); + status = CELIX_DO_IF(status, fw_getService(framework,framework->bundle, ref, (const void **) &hook)); + if (status == CELIX_SUCCESS) { + hook->added(hook->handle, infos); + } + status = CELIX_DO_IF(status, serviceRegistry_ungetService(framework->registry, framework->bundle, ref, NULL)); + status = CELIX_DO_IF(status, serviceRegistry_ungetServiceReference(framework->registry, framework->bundle, ref)); + + int i = 0; + for (i = 0; i < arrayList_size(infos); i++) { + listener_hook_info_pt info = arrayList_get(infos, i); + free(info); + } + arrayList_destroy(infos); + } + } + } + + framework_logIfError(framework->logger, status, error, "Cannot register service: %s", serviceName); + + return status; +} + +celix_status_t fw_registerServiceFactory(framework_pt framework, service_registration_pt *registration, bundle_pt bundle, const char* serviceName, service_factory_pt factory, properties_pt properties) { + celix_status_t status = CELIX_SUCCESS; + char *error = NULL; + if (serviceName == NULL || factory == NULL) { + status = CELIX_ILLEGAL_ARGUMENT; + error = "Service name and factory cannot be null"; + } + + status = CELIX_DO_IF(status, framework_acquireBundleLock(framework, bundle, OSGI_FRAMEWORK_BUNDLE_STARTING|OSGI_FRAMEWORK_BUNDLE_ACTIVE)); + status = CELIX_DO_IF(status, serviceRegistry_registerServiceFactory(framework->registry, bundle, serviceName, factory, properties, registration)); + if (!framework_releaseBundleLock(framework, bundle)) { + status = CELIX_ILLEGAL_STATE; + error = "Could not release bundle lock"; + } + + framework_logIfError(framework->logger, status, error, "Cannot register service factory: %s", serviceName); + + return CELIX_SUCCESS; +} + +celix_status_t fw_getServiceReferences(framework_pt framework, array_list_pt *references, bundle_pt bundle, const char * serviceName, const char * sfilter) { + celix_status_t status = CELIX_SUCCESS; + + filter_pt filter = NULL; + unsigned int refIdx = 0; + + if (sfilter != NULL) { + filter = filter_create(sfilter); + } + + status = CELIX_DO_IF(status, serviceRegistry_getServiceReferences(framework->registry, bundle, serviceName, filter, references)); + + if (filter != NULL) { + filter_destroy(filter); + } + + if (status == CELIX_SUCCESS) { + for (refIdx = 0; (*references != NULL) && refIdx < arrayList_size(*references); refIdx++) { + service_reference_pt ref = (service_reference_pt) arrayList_get(*references, refIdx); + service_registration_pt reg = NULL; + const char* serviceName; + properties_pt props = NULL; + status = CELIX_DO_IF(status, serviceReference_getServiceRegistration(ref, ®)); + status = CELIX_DO_IF(status, serviceRegistration_getProperties(reg, &props)); + if (status == CELIX_SUCCESS) { + serviceName = properties_get(props, OSGI_FRAMEWORK_OBJECTCLASS); + if (!serviceReference_isAssignableTo(ref, bundle, serviceName)) { + arrayList_remove(*references, refIdx); + refIdx--; + } + } + } + } + + framework_logIfError(framework->logger, status, NULL, "Failed to get service references"); + + return status; +} + +celix_status_t framework_ungetServiceReference(framework_pt framework, bundle_pt bundle, service_reference_pt reference) { + return serviceRegistry_ungetServiceReference(framework->registry, bundle, reference); +} + +celix_status_t fw_getService(framework_pt framework, bundle_pt bundle, service_reference_pt reference, const void **service) { + return serviceRegistry_getService(framework->registry, bundle, reference, service); +} + +celix_status_t fw_getBundleRegisteredServices(framework_pt framework, bundle_pt bundle, array_list_pt *services) { + return serviceRegistry_getRegisteredServices(framework->registry, bundle, services); +} + +celix_status_t fw_getBundleServicesInUse(framework_pt framework, bundle_pt bundle, array_list_pt *services) { + celix_status_t status = CELIX_SUCCESS; + status = serviceRegistry_getServicesInUse(framework->registry, bundle, services); + return status; +} + +celix_status_t framework_ungetService(framework_pt framework, bundle_pt bundle, service_reference_pt reference, bool *result) { + return serviceRegistry_ungetService(framework->registry, bundle, reference, result); +} + +void fw_addServiceListener(framework_pt framework, bundle_pt bundle, service_listener_pt listener, const char* sfilter) { + array_list_pt listenerHooks = NULL; + listener_hook_info_pt info; + unsigned int i; + + fw_service_listener_pt fwListener = (fw_service_listener_pt) calloc(1, sizeof(*fwListener)); + bundle_context_pt context = NULL; + + fwListener->bundle = bundle; + arrayList_create(&fwListener->retainedReferences); + if (sfilter != NULL) { + filter_pt filter = filter_create(sfilter); + fwListener->filter = filter; + } else { + fwListener->filter = NULL; + } + fwListener->listener = listener; + + arrayList_add(framework->serviceListeners, fwListener); + + serviceRegistry_getListenerHooks(framework->registry, framework->bundle, &listenerHooks); + + info = (listener_hook_info_pt) malloc(sizeof(*info)); + + bundle_getContext(bundle, &context); + info->context = context; + + info->removed = false; + info->filter = sfilter == NULL ? NULL : strdup(sfilter); + + for (i = 0; i < arrayList_size(listenerHooks); i++) { + service_reference_pt ref = (service_reference_pt) arrayList_get(listenerHooks, i); + listener_hook_service_pt hook = NULL; + array_list_pt infos = NULL; + bool ungetResult = false; + + fw_getService(framework, framework->bundle, ref, (const void **) &hook); + + arrayList_create(&infos); + arrayList_add(infos, info); + hook->added(hook->handle, infos); + serviceRegistry_ungetService(framework->registry, framework->bundle, ref, &ungetResult); + serviceRegistry_ungetServiceReference(framework->registry, framework->bundle, ref); + arrayList_destroy(infos); + } + + if (info->filter != NULL) { + free(info->filter); + } + free(info); + + arrayList_destroy(listenerHooks); +} + +void fw_removeServiceListener(framework_pt framework, bundle_pt bundle, service_listener_pt listener) { + listener_hook_info_pt info = NULL; + unsigned int i; + fw_service_listener_pt element; + + bundle_context_pt context; + bundle_getContext(bundle, &context); + + for (i = 0; i < arrayList_size(framework->serviceListeners); i++) { + element = (fw_service_listener_pt) arrayList_get(framework->serviceListeners, i); + if (element->listener == listener && element->bundle == bundle) { + bundle_context_pt lContext = NULL; + + info = (listener_hook_info_pt) malloc(sizeof(*info)); + + bundle_getContext(element->bundle, &lContext); + info->context = lContext; + + // TODO Filter toString; + filter_getString(element->filter, (const char**)&info->filter); + info->removed = true; + + arrayList_remove(framework->serviceListeners, i); + i--; + + //unregistering retained service references. For these refs a unregister event will not be triggered. + int k; + int rSize = arrayList_size(element->retainedReferences); + for (k = 0; k < rSize; k += 1) { + service_reference_pt ref = arrayList_get(element->retainedReferences, k); + if (ref != NULL) { + serviceRegistry_ungetServiceReference(framework->registry, element->bundle, ref); // decrease retain counter + } + } + + element->bundle = NULL; + filter_destroy(element->filter); + arrayList_destroy(element->retainedReferences); + element->filter = NULL; + element->listener = NULL; + free(element); + element = NULL; + break; + } + } + + if (info != NULL) { + unsigned int i; + array_list_pt listenerHooks = NULL; + serviceRegistry_getListenerHooks(framework->registry, framework->bundle, &listenerHooks); + + for (i = 0; i < arrayList_size(listenerHooks); i++) { + service_reference_pt ref = (service_reference_pt) arrayList_get(listenerHooks, i); + listener_hook_service_pt hook = NULL; + array_list_pt infos = NULL; + bool ungetResult; + + fw_getService(framework, framework->bundle, ref, (const void **) &hook); + + arrayList_create(&infos); + arrayList_add(infos, info); + hook->removed(hook->handle, infos); + serviceRegistry_ungetService(framework->registry, framework->bundle, ref, &ungetResult); + serviceRegistry_ungetServiceReference(framework->registry, framework->bundle, ref); + arrayList_destroy(infos); + } + + arrayList_destroy(listenerHooks); + free(info); + } +} + +celix_status_t fw_addBundleListener(framework_pt framework, bundle_pt bundle, bundle_listener_pt listener) { + celix_status_t status = CELIX_SUCCESS; + fw_bundle_listener_pt bundleListener = NULL; + + bundleListener = (fw_bundle_listener_pt) malloc(sizeof(*bundleListener)); + if (!bundleListener) { + status = CELIX_ENOMEM; + } else { + bundleListener->listener = listener; + bundleListener->bundle = bundle; + + if (celixThreadMutex_lock(&framework->bundleListenerLock) != CELIX_SUCCESS) { + status = CELIX_FRAMEWORK_EXCEPTION; + } else { + arrayList_add(framework->bundleListeners, bundleListener); + + if (celixThreadMutex_unlock(&framework->bundleListenerLock)) { + status = CELIX_FRAMEWORK_EXCEPTION; + } + } + } + + framework_logIfError(framework->logger, status, NULL, "Failed to add bundle listener"); + + return status; +} + +celix_status_t fw_removeBundleListener(framework_pt framework, bundle_pt bundle, bundle_listener_pt listener) { + celix_status_t status = CELIX_SUCCESS; + + unsigned int i; + fw_bundle_listener_pt bundleListener; + + if (celixThreadMutex_lock(&framework->bundleListenerLock) != CELIX_SUCCESS) { + status = CELIX_FRAMEWORK_EXCEPTION; + } + else { + for (i = 0; i < arrayList_size(framework->bundleListeners); i++) { + bundleListener = (fw_bundle_listener_pt) arrayList_get(framework->bundleListeners, i); + if (bundleListener->listener == listener && bundleListener->bundle == bundle) { + arrayList_remove(framework->bundleListeners, i); + + bundleListener->bundle = NULL; + bundleListener->listener = NULL; + free(bundleListener); + } + } + if (celixThreadMutex_unlock(&framework->bundleListenerLock)) { + status = CELIX_FRAMEWORK_EXCEPTION; + } + } + + framework_logIfError(framework->logger, status, NULL, "Failed to remove bundle listener"); + + return status; +} + +celix_status_t fw_addFrameworkListener(framework_pt framework, bundle_pt bundle, framework_listener_pt listener) { + celix_status_t status = CELIX_SUCCESS; + fw_framework_listener_pt frameworkListener = NULL; + + frameworkListener = (fw_framework_listener_pt) malloc(sizeof(*frameworkListener)); + if (!frameworkListener) { + status = CELIX_ENOMEM; + } else { + frameworkListener->listener = listener; + frameworkListener->bundle = bundle; + + arrayList_add(framework->frameworkListeners, frameworkListener); + } + + framework_logIfError(framework->logger, status, NULL, "Failed to add framework listener"); + + return status; +} + +celix_status_t fw_removeFrameworkListener(framework_pt framework, bundle_pt bundle, framework_listener_pt listener) { + celix_status_t status = CELIX_SUCCESS; + + unsigned int i; + fw_framework_listener_pt frameworkListener; + + for (i = 0; i < arrayList_size(framework->frameworkListeners); i++) { + frameworkListener = (fw_framework_listener_pt) arrayList_get(framework->frameworkListeners, i); + if (frameworkListener->listener == listener && frameworkListener->bundle == bundle) { + arrayList_remove(framework->frameworkListeners, i); + + frameworkListener->bundle = NULL; + frameworkListener->listener = NULL; + free(frameworkListener); + } + } + + framework_logIfError(framework->logger, status, NULL, "Failed to remove framework listener"); + + return status; +} + +void fw_serviceChanged(framework_pt framework, service_event_type_e eventType, service_registration_pt registration, properties_pt oldprops) { + unsigned int i; + fw_service_listener_pt element; + + if (arrayList_size(framework->serviceListeners) > 0) { + for (i = 0; i < arrayList_size(framework->serviceListeners); i++) { + int matched = 0; + properties_pt props = NULL; + bool matchResult = false; + + element = (fw_service_listener_pt) arrayList_get(framework->serviceListeners, i); + serviceRegistration_getProperties(registration, &props); + if (element->filter != NULL) { + filter_match(element->filter, props, &matchResult); + } + matched = (element->filter == NULL) || matchResult; + if (matched) { + service_reference_pt reference = NULL; + service_event_pt event; + + event = (service_event_pt) malloc(sizeof (*event)); + + serviceRegistry_getServiceReference(framework->registry, element->bundle, registration, &reference); + + //NOTE: that you are never sure that the UNREGISTERED event will by handle by an service_listener. listener could be gone + //Every reference retained is therefore stored and called when a service listener is removed from the framework. + if (eventType == OSGI_FRAMEWORK_SERVICE_EVENT_REGISTERED) { + serviceRegistry_retainServiceReference(framework->registry, element->bundle, reference); + arrayList_add(element->retainedReferences, reference); //TODO improve by using set (or hashmap) instead of list + } + + event->type = eventType; + event->reference = reference; + + element->listener->serviceChanged(element->listener, event); + + serviceRegistry_ungetServiceReference(framework->registry, element->bundle, reference); + + if (eventType == OSGI_FRAMEWORK_SERVICE_EVENT_UNREGISTERING) { + //if service listener was active when service was registered, release the retained reference + if (arrayList_removeElement(element->retainedReferences, reference)) { + serviceRegistry_ungetServiceReference(framework->registry, element->bundle, reference); // decrease retain counter + } + } + + free(event); + + } else if (eventType == OSGI_FRAMEWORK_SERVICE_EVENT_MODIFIED) { + bool matchResult = false; + int matched = 0; + if (element->filter != NULL) { + filter_match(element->filter, oldprops, &matchResult); + } + matched = (element->filter == NULL) || matchResult; + if (matched) { + service_reference_pt reference = NULL; + service_event_pt endmatch = (service_event_pt) malloc(sizeof (*endmatch)); + + serviceRegistry_getServiceReference(framework->registry, element->bundle, registration, &reference); + + endmatch->reference = reference; + endmatch->type = OSGI_FRAMEWORK_SERVICE_EVENT_MODIFIED_ENDMATCH; + element->listener->serviceChanged(element->listener, endmatch); + + serviceRegistry_ungetServiceReference(framework->registry, element->bundle, reference); + free(endmatch); + + } + } + } + } + +} + +//celix_status_t fw_isServiceAssignable(framework_pt fw, bundle_pt requester, service_reference_pt reference, bool *assignable) { +// celix_status_t status = CELIX_SUCCESS; +// +// *assignable = true; +// service_registration_pt registration = NULL; +// status = serviceReference_getServiceRegistration(reference, ®istration); +// if (status == CELIX_SUCCESS) { +// char *serviceName = properties_get(registration->properties, (char *) OBJECTCLASS); +// if (!serviceReference_isAssignableTo(reference, requester, serviceName)) { +// *assignable = false; +// } +// } +// +// return status; +//} + +long framework_getNextBundleId(framework_pt framework) { + long id = framework->nextBundleId; + framework->nextBundleId++; + return id; +} + +celix_status_t framework_markResolvedModules(framework_pt framework, linked_list_pt resolvedModuleWireMap) { + if (resolvedModuleWireMap != NULL) { + // hash_map_iterator_pt iterator = hashMapIterator_create(resolvedModuleWireMap); + linked_list_iterator_pt iterator = linkedListIterator_create(resolvedModuleWireMap, linkedList_size(resolvedModuleWireMap)); + while (linkedListIterator_hasPrevious(iterator)) { + importer_wires_pt iw = linkedListIterator_previous(iterator); + // hash_map_entry_pt entry = hashMapIterator_nextEntry(iterator); + module_pt module = iw->importer; + +// bundle_pt bundle = module_getBundle(module); +// bundle_archive_pt archive = NULL; +// bundle_getArchive(bundle, &archive); +// bundle_revision_pt revision = NULL; +// bundleArchive_getCurrentRevision(archive, &revision); +// char *root = NULL; +// bundleRevision_getRoot(revision, &root); +// manifest_pt manifest = NULL; +// bundleRevision_getManifest(revision, &manifest); +// +// char *private = manifest_getValue(manifest, OSGI_FRAMEWORK_PRIVATE_LIBRARY); +// char *export = manifest_getValue(manifest, OSGI_FRAMEWORK_EXPORT_LIBRARY); +// +// printf("Root %s\n", root); + + // for each library update the reference to the wires, if there are any + + linked_list_pt wires = iw->wires; + +// linked_list_iterator_pt wit = linkedListIterator_create(wires, 0); +// while (linkedListIterator_hasNext(wit)) { +// wire_pt wire = linkedListIterator_next(wit); +// module_pt importer = NULL; +// requirement_pt requirement = NULL; +// module_pt exporter = NULL; +// capability_pt capability = NULL; +// wire_getImporter(wire, &importer); +// wire_getRequirement(wire, &requirement); +// +// wire_getExporter(wire, &exporter); +// wire_getCapability(wire, &capability); +// +// char *importerName = NULL; +// module_getSymbolicName(importer, &importerName); +// +// char *exporterName = NULL; +// module_getSymbolicName(exporter, &exporterName); +// +// version_pt version = NULL; +// char *name = NULL; +// capability_getServiceName(capability, &name); +// capability_getVersion(capability, &version); +// char *versionString = NULL; +// version_toString(version, framework->mp, &versionString); +// +// printf("Module %s imports library %s:%s from %s\n", importerName, name, versionString, exporterName); +// } + + module_setWires(module, wires); + + module_setResolved(module); + resolver_moduleResolved(module); + + const char *mname = NULL; + module_getSymbolicName(module, &mname); + framework_markBundleResolved(framework, module); + linkedListIterator_remove(iterator); + free(iw); + } + linkedListIterator_destroy(iterator); + linkedList_destroy(resolvedModuleWireMap); + } + return CELIX_SUCCESS; +} + +celix_status_t framework_markBundleResolved(framework_pt framework, module_pt module) { + celix_status_t status = CELIX_SUCCESS; + bundle_pt bundle = module_getBundle(module); + bundle_state_e state; + char *error = NULL; + + if (bundle != NULL) { + framework_acquireBundleLock(framework, bundle, OSGI_FRAMEWORK_BUNDLE_INSTALLED|OSGI_FRAMEWORK_BUNDLE_RESOLVED|OSGI_FRAMEWORK_BUNDLE_ACTIVE); + bundle_getState(bundle, &state); + if (state != OSGI_FRAMEWORK_BUNDLE_INSTALLED) { + printf("Trying to resolve a resolved bundle"); + status = CELIX_ILLEGAL_STATE; + } else { + // Load libraries of this module + bool isSystemBundle = false; + bundle_isSystemBundle(bundle, &isSystemBundle); + if (!isSystemBundle) { + status = CELIX_DO_IF(status, framework_loadBundleLibraries(framework, bundle)); + } + + status = CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, bundle, OSGI_FRAMEWORK_BUNDLE_RESOLVED)); + status = CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_RESOLVED, bundle)); + } + + if (status != CELIX_SUCCESS) { + module_pt module = NULL; + const char *symbolicName = NULL; + long id = 0; + module_getSymbolicName(module, &symbolicName); + bundle_getBundleId(bundle, &id); + if (error != NULL) { + fw_logCode(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, status, "Could not start bundle: %s [%ld]; cause: %s", symbolicName, id, error); + } else { + fw_logCode(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, status, "Could not start bundle: %s [%ld]", symbolicName, id); + } + } + + framework_releaseBundleLock(framework, bundle); + } + + return CELIX_SUCCESS; +} + +array_list_pt framework_getBundles(framework_pt framework) { + array_list_pt bundles = NULL; + hash_map_iterator_pt iterator; + arrayList_create(&bundles); + + celixThreadMutex_lock(&framework->installedBundleMapLock); + + iterator = hashMapIterator_create(framework->installedBundleMap); + while (hashMapIterator_hasNext(iterator)) { + bundle_pt bundle = (bundle_pt) hashMapIterator_nextValue(iterator); + arrayList_add(bundles, bundle); + } + hashMapIterator_destroy(iterator); + + celixThreadMutex_unlock(&framework->installedBundleMapLock); + + return bundles; +} + +bundle_pt framework_getBundle(framework_pt framework, const char* location) { + celixThreadMutex_lock(&framework->installedBundleMapLock); + bundle_pt bundle = (bundle_pt) hashMap_get(framework->installedBundleMap, location); + celixThreadMutex_unlock(&framework->installedBundleMapLock); + return bundle; +} + +bundle_pt framework_getBundleById(framework_pt framework, long id) { + celixThreadMutex_lock(&framework->installedBundleMapLock); + hash_map_iterator_pt iter = hashMapIterator_create(framework->installedBundleMap); + bundle_pt bundle = NULL; + while (hashMapIterator_hasNext(iter)) { + bundle_pt b = (bundle_pt) hashMapIterator_nextValue(iter); + bundle_archive_pt archive = NULL; + long bid; + bundle_getArchive(b, &archive); + bundleArchive_getId(archive, &bid); + if (bid == id) { + bundle = b; + break; + } + } + hashMapIterator_destroy(iter); + celixThreadMutex_unlock(&framework->installedBundleMapLock); + + return bundle; +} + +celix_status_t framework_acquireInstallLock(framework_pt framework, const char * location) { + celixThreadMutex_lock(&framework->installRequestLock); + + while (hashMap_get(framework->installRequestMap, location) != NULL) { + celixThreadCondition_wait(&framework->condition, &framework->installRequestLock); + } + hashMap_put(framework->installRequestMap, (char*)location, (char*)location); + + celixThreadMutex_unlock(&framework->installRequestLock); + + return CELIX_SUCCESS; +} + +celix_status_t framework_releaseInstallLock(framework_pt framework, const char* location) { + celixThreadMutex_lock(&framework->installRequestLock); + + hashMap_remove(framework->installRequestMap, location); + celixThreadCondition_broadcast(&framework->condition); + + celixThreadMutex_unlock(&framework->installRequestLock); + + return CELIX_SUCCESS; +} + +celix_status_t framework_setBundleStateAndNotify(framework_pt framework, bundle_pt bundle, int state) { + int ret = CELIX_SUCCESS; + + int err = celixThreadMutex_lock(&framework->bundleLock); + if (err != 0) { + fw_log(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, "Failed to lock"); + return CELIX_BUNDLE_EXCEPTION; + } + + bundle_setState(bundle, state); + err = celixThreadCondition_broadcast(&framework->condition); + if (err != 0) { + fw_log(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, "Failed to broadcast"); + ret = CELIX_BUNDLE_EXCEPTION; + } + + err = celixThreadMutex_unlock(&framework->bundleLock); + if (err != 0) { + fw_log(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, "Failed to unlock"); + return CELIX_BUNDLE_EXCEPTION; + } + return ret; +} + +celix_status_t framework_acquireBundleLock(framework_pt framework, bundle_pt bundle, int desiredStates) { + celix_status_t status = CELIX_SUCCESS; + + bool locked; + celix_thread_t lockingThread = celix_thread_default; + + int err = celixThreadMutex_lock(&framework->bundleLock); + if (err != CELIX_SUCCESS) { + fw_log(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, "Failed to lock"); + status = CELIX_BUNDLE_EXCEPTION; + } else { + bool lockable = false; + bool isSelf = false; + + bundle_isLockable(bundle, &lockable); + thread_equalsSelf(framework->globalLockThread, &isSelf); + + while (!lockable + || (( celixThread_initalized(framework->globalLockThread) == true) + && !isSelf)) + { + bundle_state_e state; + bundle_getState(bundle, &state); + if ((desiredStates & state) == 0) { + status = CELIX_ILLEGAL_STATE; + break; + } + + bundle_getLockingThread(bundle, &lockingThread); + if (isSelf && (celixThread_initalized(lockingThread) == true) + && arrayList_contains(framework->globalLockWaitersList, &lockingThread)) { + framework->interrupted = true; +// celixThreadCondition_signal_thread_np(&framework->condition, bundle_getLockingThread(bundle)); + celixThreadCondition_signal(&framework->condition); + } + + celixThreadCondition_wait(&framework->condition, &framework->bundleLock); + + status = bundle_isLockable(bundle, &lockable); + if (status != CELIX_SUCCESS) { + break; + } + } + + if (status == CELIX_SUCCESS) { + bundle_state_e state; + bundle_getState(bundle, &state); + if ((desiredStates & state) == 0) { + status = CELIX_ILLEGAL_STATE; + } else { + if (bundle_lock(bundle, &locked)) { + if (!locked) { + status = CELIX_ILLEGAL_STATE; + } + } + } + } + celixThreadMutex_unlock(&framework->bundleLock); + } + + framework_logIfError(framework->logger, status, NULL, "Failed to get bundle lock"); + + return status; +} + +bool framework_releaseBundleLock(framework_pt framework, bundle_pt bundle) { + bool unlocked; + celix_thread_t lockingThread = celix_thread_default; + + celixThreadMutex_lock(&framework->bundleLock); + + bundle_unlock(bundle, &unlocked); + if (!unlocked) { + celixThreadMutex_unlock(&framework->bundleLock); + return false; + } + bundle_getLockingThread(bundle, &lockingThread); + if (celixThread_initalized(lockingThread) == false) { + celixThreadCondition_broadcast(&framework->condition); + } + + celixThreadMutex_unlock(&framework->bundleLock); + + return true; +} + +bool framework_acquireGlobalLock(framework_pt framework) { + bool interrupted = false; + bool isSelf = false; + + celixThreadMutex_lock(&framework->bundleLock); + + thread_equalsSelf(framework->globalLockThread, &isSelf); + + while (!interrupted + && (celixThread_initalized(framework->globalLockThread) == true) + && (!isSelf)) { + celix_thread_t currentThread = celixThread_self(); + arrayList_add(framework->globalLockWaitersList, ¤tThread); + celixThreadCondition_broadcast(&framework->condition); + + celixThreadCondition_wait(&framework->condition, &framework->bundleLock); + if (framework->interrupted) { + interrupted = true; + framework->interrupted = false; + } + + arrayList_removeElement(framework->globalLockWaitersList, ¤tThread); + } + + if (!interrupted) { + framework->globalLockCount++; + framework->globalLockThread = celixThread_self(); + } + + celixThreadMutex_unlock(&framework->bundleLock); + + return !interrupted; +} + +celix_status_t framework_releaseGlobalLock(framework_pt framework) { + int status = CELIX_SUCCESS; + if (celixThreadMutex_lock(&framework->bundleLock) != 0) { + fw_log(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, "Error locking framework bundle lock"); + return CELIX_FRAMEWORK_EXCEPTION; + } + + if (celixThread_equals(framework->globalLockThread, celixThread_self())) { + framework->globalLockCount--; + if (framework->globalLockCount == 0) { + framework->globalLockThread = celix_thread_default; + if (celixThreadCondition_broadcast(&framework->condition) != 0) { + fw_log(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, "Failed to broadcast global lock release."); + status = CELIX_FRAMEWORK_EXCEPTION; + // still need to unlock before returning + } + } + } else { + printf("The current thread does not own the global lock"); + } + + if (celixThreadMutex_unlock(&framework->bundleLock) != 0) { + fw_log(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, "Error unlocking framework bundle lock"); + return CELIX_FRAMEWORK_EXCEPTION; + } + + framework_logIfError(framework->logger, status, NULL, "Failed to release global lock"); + + return status; +} + +celix_status_t framework_waitForStop(framework_pt framework) { + if (celixThreadMutex_lock(&framework->mutex) != 0) { + fw_log(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, "Error locking the framework, shutdown gate not set."); + return CELIX_FRAMEWORK_EXCEPTION; + } + while (!framework->shutdown) { + celix_status_t status = celixThreadCondition_wait(&framework->shutdownGate, &framework->mutex); + if (status != 0) { + fw_log(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, "Error waiting for shutdown gate."); + return CELIX_FRAMEWORK_EXCEPTION; + } + } + if (celixThreadMutex_unlock(&framework->mutex) != 0) { + fw_log(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, "Error unlocking the framework."); + return CELIX_FRAMEWORK_EXCEPTION; + } + + celixThread_join(framework->shutdownThread, NULL); + + fw_log(framework->logger, OSGI_FRAMEWORK_LOG_INFO, "FRAMEWORK: Successful shutdown"); + return CELIX_SUCCESS; +} + +static void *framework_shutdown(void *framework) { + framework_pt fw = (framework_pt) framework; + int err; + + fw_log(fw->logger, OSGI_FRAMEWORK_LOG_INFO, "FRAMEWORK: Shutdown"); + celixThreadMutex_lock(&fw->installedBundleMapLock); + + hash_map_iterator_pt iter = hashMapIterator_create(fw->installedBundleMap); + bundle_pt bundle = NULL; + while ((bundle = hashMapIterator_nextValue(iter)) != NULL) { + bundle_state_e state; + bundle_getState(bundle, &state); + if (state == OSGI_FRAMEWORK_BUNDLE_ACTIVE || state == OSGI_FRAMEWORK_BUNDLE_STARTING) { + celixThreadMutex_unlock(&fw->installedBundleMapLock); + fw_stopBundle(fw, bundle, 0); + celixThreadMutex_lock(&fw->installedBundleMapLock); + hashMapIterator_destroy(iter); + iter = hashMapIterator_create(fw->installedBundleMap); + } + } + hashMapIterator_destroy(iter); + + iter = hashMapIterator_create(fw->installedBundleMap); + bundle = NULL; + while ((bundle = hashMapIterator_nextValue(iter)) != NULL) { + bundle_close(bundle); + } + hashMapIterator_destroy(iter); + celixThreadMutex_unlock(&fw->installedBundleMapLock); + + err = celixThreadMutex_lock(&fw->mutex); + if (err != 0) { + fw_log(fw->logger, OSGI_FRAMEWORK_LOG_ERROR, "Error locking the framework, cannot exit clean."); + celixThread_exit(NULL); + return NULL; + } + + if (celixThreadMutex_lock(&fw->dispatcherLock) != CELIX_SUCCESS) { + fw_log(fw->logger, OSGI_FRAMEWORK_LOG_ERROR, "Error locking the dispatcherThread."); + } + else { + fw->shutdown = true; + + if (celixThreadCondition_broadcast(&fw->dispatcher)) { + fw_log(fw->logger, OSGI_FRAMEWORK_LOG_ERROR, "Error broadcasting ."); + } + + if (celixThreadMutex_unlock(&fw->dispatcherLock)) { + fw_log(fw->logger, OSGI_FRAMEWORK_LOG_ERROR, "Error unlocking the dispatcherThread."); + } + + celixThread_join(fw->dispatcherThread, NULL); + } + + + err = celixThreadCondition_broadcast(&fw->shutdownGate); + if (err != 0) { + fw_log(fw->logger, OSGI_FRAMEWORK_LOG_ERROR, "Error waking the shutdown gate, cannot exit clean."); + err = celixThreadMutex_unlock(&fw->mutex); + if (err != 0) { + fw_log(fw->logger, OSGI_FRAMEWORK_LOG_ERROR, "Error unlocking the framework, cannot exit clean."); + } + + celixThread_exit(NULL); + return NULL; + } + err = celixThreadMutex_unlock(&fw->mutex); + if (err != 0) { +// fw_log(fw->logger, OSGI_FRAMEWORK_LOG_ERROR, "Error unlocking the framework, cannot exit clean."); + } + +// fw_log(fw->logger, OSGI_FRAMEWORK_LOG_INFO, "FRAMEWORK: Shutdown done\n"); + celixThread_exit((void *) CELIX_SUCCESS); + + return NULL; +} + +celix_status_t framework_getFrameworkBundle(framework_pt framework, bundle_pt *bundle) { + celix_status_t status = CELIX_SUCCESS; + + if (framework != NULL && *bundle == NULL) { + *bundle = framework->bundle; + } else { + status = CELIX_ILLEGAL_ARGUMENT; + } + + return status; +} + +celix_status_t fw_fireBundleEvent(framework_pt framework, bundle_event_type_e eventType, bundle_pt bundle) { + celix_status_t status = CELIX_SUCCESS; + + if ((eventType != OSGI_FRAMEWORK_BUNDLE_EVENT_STARTING) + && (eventType != OSGI_FRAMEWORK_BUNDLE_EVENT_STOPPING) + && (eventType != OSGI_FRAMEWORK_BUNDLE_EVENT_LAZY_ACTIVATION)) { + request_pt request = (request_pt) calloc(1, sizeof(*request)); + if (!request) { + status = CELIX_ENOMEM; + } else { + bundle_archive_pt archive = NULL; + module_pt module = NULL; + + request->eventType = eventType; + request->filter = NULL; + request->listeners = framework->bundleListeners; + request->type = BUNDLE_EVENT_TYPE; + request->error = NULL; + request->bundleId = -1; + + status = bundle_getArchive(bundle, &archive); + + if (status == CELIX_SUCCESS) { + long bundleId; + + status = bundleArchive_getId(archive, &bundleId); + + if (status == CELIX_SUCCESS) { + request->bundleId = bundleId; + } + } + + if (status == CELIX_SUCCESS) { + status = bundle_getCurrentModule(bundle, &module); + + if (status == CELIX_SUCCESS) { + const char *symbolicName = NULL; + status = module_getSymbolicName(module, &symbolicName); + if (status == CELIX_SUCCESS) { + request->bundleSymbolicName = strdup(symbolicName); + } + } + } + + if (celixThreadMutex_lock(&framework->dispatcherLock) != CELIX_SUCCESS) { + status = CELIX_FRAMEWORK_EXCEPTION; + } else { + arrayList_add(framework->requests, request); +
<TRUNCATED>
