blob: a9d19f84de7d78e236f212e7ea749b8f7db6796d [file] [log] [blame]
/**
*Licensed to the Apache Software Foundation (ASF) under one
*or more contributor license agreements. See the NOTICE file
*distributed with this work for additional information
*regarding copyright ownership. The ASF licenses this file
*to you under the Apache License, Version 2.0 (the
*"License"); you may not use this file except in compliance
*with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*Unless required by applicable law or agreed to in writing,
*software distributed under the License is distributed on an
*"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
*specific language governing permissions and limitations
*under the License.
*/
/*
* framework.c
*
* \date Mar 23, 2010
* \author <a href="mailto:dev@celix.apache.org">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, &reg));
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, &registration);
// 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, &currentThread);
celixThreadCondition_broadcast(&framework->condition);
celixThreadCondition_wait(&framework->condition, &framework->bundleLock);
if (framework->interrupted) {
interrupted = true;
framework->interrupted = false;
}
arrayList_removeElement(framework->globalLockWaitersList, &currentThread);
}
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);
celix_status_t bcast_status = celixThreadCondition_broadcast(&framework->dispatcher);
celix_status_t unlock_status = celixThreadMutex_unlock(&framework->dispatcherLock);
if (bcast_status!=0 || unlock_status!=0) {
status = CELIX_FRAMEWORK_EXCEPTION;
}
}
}
}
framework_logIfError(framework->logger, status, NULL, "Failed to fire bundle event");
return status;
}
celix_status_t fw_fireFrameworkEvent(framework_pt framework, framework_event_type_e eventType, bundle_pt bundle, celix_status_t errorCode) {
celix_status_t status = CELIX_SUCCESS;
request_pt request = (request_pt) malloc(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->frameworkListeners;
request->type = FRAMEWORK_EVENT_TYPE;
request->errorCode = errorCode;
request->error = "";
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 (errorCode != CELIX_SUCCESS) {
char message[256];
celix_strerror(errorCode, message, 256);
request->error = message;
}
if (celixThreadMutex_lock(&framework->dispatcherLock) != CELIX_SUCCESS) {
status = CELIX_FRAMEWORK_EXCEPTION;
} else {
arrayList_add(framework->requests, request);
celix_status_t bcast_status = celixThreadCondition_broadcast(&framework->dispatcher);
celix_status_t unlock_status = celixThreadMutex_unlock(&framework->dispatcherLock);
if (bcast_status!=0 || unlock_status!=0) {
status = CELIX_FRAMEWORK_EXCEPTION;
}
}
}
framework_logIfError(framework->logger, status, NULL, "Failed to fire framework event");
return status;
}
static void *fw_eventDispatcher(void *fw) {
framework_pt framework = (framework_pt) fw;
while (true) {
int size;
celix_status_t status;
if (celixThreadMutex_lock(&framework->dispatcherLock) != 0) {
fw_log(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, "Error locking the dispatcher");
celixThread_exit(NULL);
return NULL;
}
size = arrayList_size(framework->requests);
while (size == 0 && !framework->shutdown) {
celixThreadCondition_wait(&framework->dispatcher, &framework->dispatcherLock);
// Ignore status and just keep waiting
size = arrayList_size(framework->requests);
}
if (size == 0 && framework->shutdown) {
celixThreadMutex_unlock(&framework->dispatcherLock);
celixThread_exit(NULL);
return NULL;
}
request_pt request = (request_pt) arrayList_remove(framework->requests, 0);
if ((status = celixThreadMutex_unlock(&framework->dispatcherLock)) != 0) {
fw_log(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, "Error unlocking the dispatcher.");
celixThread_exit(NULL);
return NULL;
}
if (celixThreadMutex_lock(&framework->bundleListenerLock) != CELIX_SUCCESS) {
status = CELIX_FRAMEWORK_EXCEPTION;
} else if (celixThreadMutex_lock(&framework->bundleLock) != CELIX_SUCCESS) {
celixThreadMutex_unlock(&framework->bundleListenerLock);
status = CELIX_FRAMEWORK_EXCEPTION;
} else {
int i;
int size = arrayList_size(request->listeners);
for (i = 0; i < size; i++) {
if (request->type == BUNDLE_EVENT_TYPE) {
fw_bundle_listener_pt listener = (fw_bundle_listener_pt) arrayList_get(request->listeners, i);
bundle_event_pt event = (bundle_event_pt) calloc(1, sizeof(*event));
event->bundleId = request->bundleId;
event->bundleSymbolicName = strdup(request->bundleSymbolicName);
event->type = request->eventType;
fw_invokeBundleListener(framework, listener->listener, event, listener->bundle);
free(event->bundleSymbolicName);
free(event);
} else if (request->type == FRAMEWORK_EVENT_TYPE) {
fw_framework_listener_pt listener = (fw_framework_listener_pt) arrayList_get(request->listeners, i);
framework_event_pt event = (framework_event_pt) calloc(1, sizeof(*event));
event->bundleId = request->bundleId;
event->bundleSymbolicName = strdup(request->bundleSymbolicName);
event->type = request->eventType;
event->error = request->error;
event->errorCode = request->errorCode;
fw_invokeFrameworkListener(framework, listener->listener, event, listener->bundle);
free(event);
}
}
if (celixThreadMutex_unlock(&framework->bundleLock)) {
status = CELIX_FRAMEWORK_EXCEPTION;
}
if (celixThreadMutex_unlock(&framework->bundleListenerLock)) {
status = CELIX_FRAMEWORK_EXCEPTION;
}
free(request->bundleSymbolicName);
free(request);
}
}
celixThread_exit(NULL);
return NULL;
}
celix_status_t fw_invokeBundleListener(framework_pt framework, bundle_listener_pt listener, bundle_event_pt event, bundle_pt bundle) {
// We only support async bundle listeners for now
bundle_state_e state;
celix_status_t ret = bundle_getState(bundle, &state);
if (state == OSGI_FRAMEWORK_BUNDLE_STARTING || state == OSGI_FRAMEWORK_BUNDLE_ACTIVE) {
listener->bundleChanged(listener, event);
}
return ret;
}
celix_status_t fw_invokeFrameworkListener(framework_pt framework, framework_listener_pt listener, framework_event_pt event, bundle_pt bundle) {
bundle_state_e state;
celix_status_t ret = bundle_getState(bundle, &state);
if (state == OSGI_FRAMEWORK_BUNDLE_STARTING || state == OSGI_FRAMEWORK_BUNDLE_ACTIVE) {
listener->frameworkEvent(listener, event);
}
return ret;
}
static celix_status_t frameworkActivator_start(void * userData, bundle_context_pt context) {
// nothing to do
return CELIX_SUCCESS;
}
static celix_status_t frameworkActivator_stop(void * userData, bundle_context_pt context) {
celix_status_t status = CELIX_SUCCESS;
framework_pt framework;
if (bundleContext_getFramework(context, &framework) == CELIX_SUCCESS) {
fw_log(framework->logger, OSGI_FRAMEWORK_LOG_INFO, "FRAMEWORK: Start shutdownthread");
if (celixThread_create(&framework->shutdownThread, NULL, &framework_shutdown, framework) != CELIX_SUCCESS) {
fw_log(framework->logger, OSGI_FRAMEWORK_LOG_ERROR, "Could not create shutdown thread, normal exit not possible.");
status = CELIX_FRAMEWORK_EXCEPTION;
}
} else {
status = CELIX_FRAMEWORK_EXCEPTION;
}
framework_logIfError(framework->logger, status, NULL, "Failed to stop framework activator");
return status;
}
static celix_status_t frameworkActivator_destroy(void * userData, bundle_context_pt context) {
return CELIX_SUCCESS;
}
static celix_status_t framework_loadBundleLibraries(framework_pt framework, bundle_pt bundle) {
celix_status_t status = CELIX_SUCCESS;
handle_t handle = NULL;
bundle_archive_pt archive = NULL;
bundle_revision_pt revision = NULL;
manifest_pt manifest = NULL;
status = CELIX_DO_IF(status, bundle_getArchive(bundle, &archive));
status = CELIX_DO_IF(status, bundleArchive_getCurrentRevision(archive, &revision));
status = CELIX_DO_IF(status, bundleRevision_getManifest(revision, &manifest));
if (status == CELIX_SUCCESS) {
const char *privateLibraries = NULL;
const char *exportLibraries = NULL;
const char *activator = NULL;
privateLibraries = manifest_getValue(manifest, OSGI_FRAMEWORK_PRIVATE_LIBRARY);
exportLibraries = manifest_getValue(manifest, OSGI_FRAMEWORK_EXPORT_LIBRARY);
activator = manifest_getValue(manifest, OSGI_FRAMEWORK_BUNDLE_ACTIVATOR);
if (exportLibraries != NULL) {
status = CELIX_DO_IF(status, framework_loadLibraries(framework, exportLibraries, activator, archive, &handle));
}
if (privateLibraries != NULL) {
status = CELIX_DO_IF(status,
framework_loadLibraries(framework, privateLibraries, activator, archive, &handle));
}
if (status == CELIX_SUCCESS) {
bundle_setHandle(bundle, handle);
}
else if(handle != NULL){
fw_closeLibrary(handle);
}
}
framework_logIfError(framework->logger, status, NULL, "Could not load all bundle libraries");
return status;
}
static celix_status_t framework_loadLibraries(framework_pt framework, const char *librariesIn, const char *activator, bundle_archive_pt archive, void **activatorHandle) {
celix_status_t status = CELIX_SUCCESS;
char* last;
char* libraries = strndup(librariesIn, 1024*10);
char* token = strtok_r(libraries, ",", &last);
while (token != NULL) {
void *handle = NULL;
char lib[128];
lib[127] = '\0';
char *path;
char *pathToken = strtok_r(token, ";", &path);
strncpy(lib, pathToken, 127);
pathToken = strtok_r(NULL, ";", &path);
while (pathToken != NULL) {
/*Disable version should be part of the lib name
if (strncmp(pathToken, "version", 7) == 0) {
char *ver = strdup(pathToken);
char version[strlen(ver) - 9];
strncpy(version, ver+9, strlen(ver) - 10);
version[strlen(ver) - 10] = '\0';
strcat(lib, "-");
strcat(lib, version);
}*/
pathToken = strtok_r(NULL, ";", &path);
}
char *trimmedLib = utils_stringTrim(lib);
status = framework_loadLibrary(framework, trimmedLib, archive, &handle);
if ( (status == CELIX_SUCCESS) && (activator != NULL) && (strcmp(trimmedLib, activator) == 0) ) {
*activatorHandle = handle;
}
else if(handle!=NULL){
fw_closeLibrary(handle);
}
token = strtok_r(NULL, ",", &last);
}
framework_logIfError(framework->logger, status, NULL, "Could not load all libraries");
free(libraries);
return status;
}
static celix_status_t framework_loadLibrary(framework_pt framework, const char *library, bundle_archive_pt archive, void **handle) {
celix_status_t status = CELIX_SUCCESS;
char *error = NULL;
#ifdef __linux__
char * library_prefix = "lib";
char * library_extension = ".so";
#elif __APPLE__
char * library_prefix = "lib";
char * library_extension = ".dylib";
#elif WIN32
char * library_prefix = "";
char * library_extension = ".dll";
#endif
char libraryPath[256];
long refreshCount = 0;
const char *archiveRoot = NULL;
long revisionNumber = 0;
status = CELIX_DO_IF(status, bundleArchive_getRefreshCount(archive, &refreshCount));
status = CELIX_DO_IF(status, bundleArchive_getArchiveRoot(archive, &archiveRoot));
status = CELIX_DO_IF(status, bundleArchive_getCurrentRevisionNumber(archive, &revisionNumber));
memset(libraryPath, 0, 256);
int written = 0;
if (strncmp("lib", library, 3) == 0) {
written = snprintf(libraryPath, 256, "%s/version%ld.%ld/%s", archiveRoot, refreshCount, revisionNumber, library);
} else {
written = snprintf(libraryPath, 256, "%s/version%ld.%ld/%s%s%s", archiveRoot, refreshCount, revisionNumber, library_prefix, library, library_extension);
}
if (written >= 256) {
error = "library path is too long";
status = CELIX_FRAMEWORK_EXCEPTION;
} else {
*handle = fw_openLibrary(libraryPath);
if (*handle == NULL) {
error = fw_getLastError();
status = CELIX_BUNDLE_EXCEPTION;
} else {
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){
arrayList_add(handles, *handle);
}
}
}
framework_logIfError(framework->logger, status, error, "Could not load library: %s", libraryPath);
return status;
}