blob: a0e6b3d775196efb576ee7faf6ba6ca477c887d0 [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.
*/
/*
* bundle.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 <string.h>
#include "framework_private.h"
#include "bundle_private.h"
#include "resolver.h"
#include "utils.h"
celix_status_t bundle_createModule(bundle_pt bundle, module_pt *module);
celix_status_t bundle_closeRevisions(bundle_pt bundle);
celix_status_t bundle_create(bundle_pt * bundle) {
celix_status_t status;
bundle_archive_pt archive = NULL;
*bundle = (bundle_pt) malloc(sizeof(**bundle));
if (*bundle == NULL) {
return CELIX_ENOMEM;
}
status = bundleArchive_createSystemBundleArchive(&archive);
if (status == CELIX_SUCCESS) {
module_pt module;
(*bundle)->archive = archive;
(*bundle)->activator = NULL;
(*bundle)->context = NULL;
(*bundle)->framework = NULL;
(*bundle)->state = OSGI_FRAMEWORK_BUNDLE_INSTALLED;
(*bundle)->modules = NULL;
arrayList_create(&(*bundle)->modules);
(*bundle)->handle = NULL;
(*bundle)->manifest = NULL;
module = module_createFrameworkModule((*bundle));
bundle_addModule(*bundle, module);
status = celixThreadMutex_create(&(*bundle)->lock, NULL);
if (status != CELIX_SUCCESS) {
status = CELIX_ILLEGAL_STATE;
} else {
(*bundle)->lockCount = 0;
(*bundle)->lockThread = celix_thread_default;
}
}
framework_logIfError(logger, status, NULL, "Failed to create bundle");
return status;
}
celix_status_t bundle_createFromArchive(bundle_pt * bundle, framework_pt framework, bundle_archive_pt archive) {
module_pt module;
celix_status_t status;
*bundle = (bundle_pt) malloc(sizeof(**bundle));
if (*bundle == NULL) {
return CELIX_ENOMEM;
}
(*bundle)->archive = archive;
(*bundle)->activator = NULL;
(*bundle)->context = NULL;
(*bundle)->handle = NULL;
(*bundle)->manifest = NULL;
(*bundle)->framework = framework;
(*bundle)->state = OSGI_FRAMEWORK_BUNDLE_INSTALLED;
(*bundle)->modules = NULL;
arrayList_create(&(*bundle)->modules);
status = bundle_createModule(*bundle, &module);
if (status == CELIX_SUCCESS) {
bundle_addModule(*bundle, module);
status = celixThreadMutex_create(&(*bundle)->lock, NULL);
if (status != CELIX_SUCCESS) {
status = CELIX_ILLEGAL_STATE;
} else {
(*bundle)->lockCount = 0;
(*bundle)->lockThread = celix_thread_default;
}
} else {
status = CELIX_FILE_IO_EXCEPTION;
}
framework_logIfError(logger, status, NULL, "Failed to create bundle");
return status;
}
celix_status_t bundle_destroy(bundle_pt bundle) {
array_list_iterator_pt iter = arrayListIterator_create(bundle->modules);
while (arrayListIterator_hasNext(iter)) {
module_pt module = arrayListIterator_next(iter);
module_destroy(module);
}
arrayListIterator_destroy(iter);
arrayList_destroy(bundle->modules);
celixThreadMutex_destroy(&bundle->lock);
free(bundle);
return CELIX_SUCCESS;
}
celix_status_t bundle_getArchive(bundle_pt bundle, bundle_archive_pt *archive) {
celix_status_t status = CELIX_SUCCESS;
if (bundle != NULL && *archive == NULL) {
*archive = bundle->archive;
} else {
status = CELIX_ILLEGAL_ARGUMENT;
}
framework_logIfError(logger, status, NULL, "Failed to get bundle archive");
return status;
}
celix_status_t bundle_getCurrentModule(bundle_pt bundle, module_pt *module) {
celix_status_t status = CELIX_SUCCESS;
if (bundle == NULL || arrayList_size(bundle->modules)==0 ) {
status = CELIX_ILLEGAL_ARGUMENT;
} else {
*module = arrayList_get(bundle->modules, arrayList_size(bundle->modules) - 1);
}
return status;
}
array_list_pt bundle_getModules(bundle_pt bundle) {
return bundle->modules;
}
void * bundle_getHandle(bundle_pt bundle) {
return bundle->handle;
}
void bundle_setHandle(bundle_pt bundle, void * handle) {
bundle->handle = handle;
}
activator_pt bundle_getActivator(bundle_pt bundle) {
return bundle->activator;
}
celix_status_t bundle_setActivator(bundle_pt bundle, activator_pt activator) {
bundle->activator = activator;
return CELIX_SUCCESS;
}
celix_status_t bundle_getContext(bundle_pt bundle, bundle_context_pt *context) {
*context = bundle->context;
return CELIX_SUCCESS;
}
celix_status_t bundle_setContext(bundle_pt bundle, bundle_context_pt context) {
bundle->context = context;
return CELIX_SUCCESS;
}
celix_status_t bundle_getEntry(bundle_pt bundle, const char* name, char** entry) {
return framework_getBundleEntry(bundle->framework, bundle, name, entry);
}
celix_status_t bundle_getState(bundle_pt bundle, bundle_state_e *state) {
if(bundle==NULL){
*state = OSGI_FRAMEWORK_BUNDLE_UNKNOWN;
return CELIX_BUNDLE_EXCEPTION;
}
*state = bundle->state;
return CELIX_SUCCESS;
}
celix_status_t bundle_setState(bundle_pt bundle, bundle_state_e state) {
bundle->state = state;
return CELIX_SUCCESS;
}
celix_status_t bundle_createModule(bundle_pt bundle, module_pt *module) {
celix_status_t status = CELIX_SUCCESS;
bundle_archive_pt archive = NULL;
bundle_revision_pt revision = NULL;
manifest_pt headerMap = 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, &headerMap));
if (status == CELIX_SUCCESS) {
long bundleId = 0;
status = bundleArchive_getId(bundle->archive, &bundleId);
if (status == CELIX_SUCCESS) {
int revision = 0;
char moduleId[512];
snprintf(moduleId, sizeof(moduleId), "%ld.%d", bundleId, revision);
*module = module_create(headerMap, moduleId, bundle);
if (*module != NULL) {
version_pt bundleVersion = module_getVersion(*module);
const char * symName = NULL;
status = module_getSymbolicName(*module, &symName);
if (status == CELIX_SUCCESS) {
array_list_pt bundles = framework_getBundles(bundle->framework);
unsigned int i;
for (i = 0; i < arrayList_size(bundles); i++) {
bundle_pt check = (bundle_pt) arrayList_get(bundles, i);
long id;
if (bundleArchive_getId(check->archive, &id) == CELIX_SUCCESS) {
if (id != bundleId) {
module_pt mod = NULL;
const char * sym = NULL;
version_pt version;
int cmp;
status = bundle_getCurrentModule(check, &mod);
status = module_getSymbolicName(mod, &sym);
version = module_getVersion(mod);
version_compareTo(bundleVersion, version, &cmp);
if ((symName != NULL) && (sym != NULL) && !strcmp(symName, sym) &&
!cmp) {
char *versionString = NULL;
version_toString(version, &versionString);
printf("Bundle symbolic name and version are not unique: %s:%s\n", sym, versionString);
free(versionString);
status = CELIX_BUNDLE_EXCEPTION;
break;
}
}
}
}
arrayList_destroy(bundles);
}
}
}
}
framework_logIfError(logger, status, NULL, "Failed to create module");
return status;
}
celix_status_t bundle_start(bundle_pt bundle) {
return bundle_startWithOptions(bundle, 0);
}
celix_status_t bundle_startWithOptions(bundle_pt bundle, int options) {
celix_status_t status = CELIX_SUCCESS;
if (bundle != NULL) {
bool systemBundle = false;
status = bundle_isSystemBundle(bundle, &systemBundle);
if (status == CELIX_SUCCESS) {
if (systemBundle) {
framework_start(bundle->framework);
} else {
status = fw_startBundle(bundle->framework, bundle, options);
}
}
}
framework_logIfError(logger, status, NULL, "Failed to start bundle");
return status;
}
celix_status_t bundle_update(bundle_pt bundle, const char *inputFile) {
celix_status_t status = CELIX_SUCCESS;
if (bundle != NULL) {
bool systemBundle = false;
status = bundle_isSystemBundle(bundle, &systemBundle);
if (status == CELIX_SUCCESS) {
if (systemBundle) {
// #TODO: Support framework update
status = CELIX_BUNDLE_EXCEPTION;
} else {
status = framework_updateBundle(bundle->framework, bundle, inputFile);
}
}
}
framework_logIfError(logger, status, NULL, "Failed to update bundle");
return status;
}
celix_status_t bundle_stop(bundle_pt bundle) {
return bundle_stopWithOptions(bundle, 0);
}
celix_status_t bundle_stopWithOptions(bundle_pt bundle, int options) {
celix_status_t status = CELIX_SUCCESS;
if (bundle != NULL) {
bool systemBundle = false;
status = bundle_isSystemBundle(bundle, &systemBundle);
if (status == CELIX_SUCCESS) {
if (systemBundle) {
framework_stop(bundle->framework);
} else {
status = fw_stopBundle(bundle->framework, bundle, options);
}
}
}
framework_logIfError(logger, status, NULL, "Failed to stop bundle");
return status;
}
celix_status_t bundle_uninstall(bundle_pt bundle) {
celix_status_t status = CELIX_SUCCESS;
if (bundle != NULL) {
bool systemBundle = false;
status = bundle_isSystemBundle(bundle, &systemBundle);
if (status == CELIX_SUCCESS) {
if (systemBundle) {
status = CELIX_BUNDLE_EXCEPTION;
} else {
status = fw_uninstallBundle(bundle->framework, bundle);
}
}
}
framework_logIfError(logger, status, NULL, "Failed to uninstall bundle");
return status;
}
celix_status_t bundle_setPersistentStateInactive(bundle_pt bundle) {
celix_status_t status;
bool systemBundle;
status = bundle_isSystemBundle(bundle, &systemBundle);
if (status == CELIX_SUCCESS) {
if (!systemBundle) {
status = bundleArchive_setPersistentState(bundle->archive, OSGI_FRAMEWORK_BUNDLE_INSTALLED);
}
}
framework_logIfError(logger, status, NULL, "Failed to set persistent state to inactive");
return status;
}
celix_status_t bundle_setPersistentStateUninstalled(bundle_pt bundle) {
celix_status_t status;
bool systemBundle;
status = bundle_isSystemBundle(bundle, &systemBundle);
if (status == CELIX_SUCCESS) {
if (!systemBundle) {
status = bundleArchive_setPersistentState(bundle->archive, OSGI_FRAMEWORK_BUNDLE_UNINSTALLED);
}
}
framework_logIfError(logger, status, NULL, "Failed to set persistent state to uninstalled");
return status;
}
celix_status_t bundle_revise(bundle_pt bundle, const char * location, const char *inputFile) {
celix_status_t status;
bundle_archive_pt archive = NULL;
status = bundle_getArchive(bundle, &archive);
if (status == CELIX_SUCCESS) {
status = bundleArchive_revise(archive, location, inputFile);
if (status == CELIX_SUCCESS) {
module_pt module;
status = bundle_createModule(bundle, &module);
if (status == CELIX_SUCCESS) {
status = bundle_addModule(bundle, module);
} else {
bool rolledback;
status = bundleArchive_rollbackRevise(archive, &rolledback);
if (status == CELIX_SUCCESS) {
status = CELIX_BUNDLE_EXCEPTION;
}
}
}
}
framework_logIfError(logger, status, NULL, "Failed to revise bundle");
return status;
}
//bool bundle_rollbackRevise(bundle_pt bundle) {
// module_pt module = arrayList_remove(bundle->modules, arrayList_set(bundle->modules) - 1);
// return resolver_removeModule(module);
//}
celix_status_t bundle_addModule(bundle_pt bundle, module_pt module) {
arrayList_add(bundle->modules, module);
resolver_addModule(module);
return CELIX_SUCCESS;
}
celix_status_t bundle_isSystemBundle(bundle_pt bundle, bool *systemBundle) {
celix_status_t status;
long bundleId;
bundle_archive_pt archive = NULL;
status = bundle_getArchive(bundle, &archive);
if (status == CELIX_SUCCESS) {
status = bundleArchive_getId(archive, &bundleId);
if (status == CELIX_SUCCESS) {
*systemBundle = (bundleId == 0);
}
}
framework_logIfError(logger, status, NULL, "Failed to check if bundle is the systembundle");
return status;
}
celix_status_t bundle_isLockable(bundle_pt bundle, bool *lockable) {
celix_status_t status;
status = celixThreadMutex_lock(&bundle->lock);
if (status != CELIX_SUCCESS) {
status = CELIX_BUNDLE_EXCEPTION;
} else {
bool equals;
status = thread_equalsSelf(bundle->lockThread, &equals);
if (status == CELIX_SUCCESS) {
*lockable = (bundle->lockCount == 0) || (equals);
}
status = celixThreadMutex_unlock(&bundle->lock);
if (status != CELIX_SUCCESS) {
status = CELIX_BUNDLE_EXCEPTION;
}
}
framework_logIfError(logger, status, NULL, "Failed to check if bundle is lockable");
return status;
}
celix_status_t bundle_getLockingThread(bundle_pt bundle, celix_thread_t *thread) {
celix_status_t status;
status = celixThreadMutex_lock(&bundle->lock);
if (status != CELIX_SUCCESS) {
status = CELIX_BUNDLE_EXCEPTION;
} else {
*thread = bundle->lockThread;
status = celixThreadMutex_unlock(&bundle->lock);
if (status != CELIX_SUCCESS) {
status = CELIX_BUNDLE_EXCEPTION;
}
}
framework_logIfError(logger, status, NULL, "Failed to get locking thread");
return status;
}
celix_status_t bundle_lock(bundle_pt bundle, bool *locked) {
celix_status_t status;
bool equals;
celixThreadMutex_lock(&bundle->lock);
status = thread_equalsSelf(bundle->lockThread, &equals);
if (status == CELIX_SUCCESS) {
if ((bundle->lockCount > 0) && !equals) {
*locked = false;
} else {
bundle->lockCount++;
bundle->lockThread = celixThread_self();
*locked = true;
}
}
celixThreadMutex_unlock(&bundle->lock);
framework_logIfError(logger, status, NULL, "Failed to lock bundle");
return status;
}
celix_status_t bundle_unlock(bundle_pt bundle, bool *unlocked) {
celix_status_t status = CELIX_SUCCESS;
bool equals;
celixThreadMutex_lock(&bundle->lock);
if (bundle->lockCount == 0) {
*unlocked = false;
} else {
status = thread_equalsSelf(bundle->lockThread, &equals);
if (status == CELIX_SUCCESS) {
if ((bundle->lockCount > 0) && !equals) {
*unlocked = false;
}
else{
bundle->lockCount--;
if (bundle->lockCount == 0) {
bundle->lockThread = celix_thread_default;
}
*unlocked = true;
}
}
}
celixThreadMutex_unlock(&bundle->lock);
framework_logIfError(logger, status, NULL, "Failed to unlock bundle");
return status;
}
celix_status_t bundle_close(bundle_pt bundle) {
bundle_archive_pt archive = NULL;
celix_status_t status;
bundle_closeModules(bundle);
bundle_closeRevisions(bundle);
status = bundle_getArchive(bundle, &archive);
if (status == CELIX_SUCCESS) {
bundleArchive_close(archive);
}
framework_logIfError(logger, status, NULL, "Failed to close bundle");
return status;
}
celix_status_t bundle_closeAndDelete(bundle_pt bundle) {
celix_status_t status;
bundle_archive_pt archive = NULL;
bundle_closeModules(bundle);
bundle_closeRevisions(bundle);
status = bundle_getArchive(bundle, &archive);
if (status == CELIX_SUCCESS) {
bundleArchive_closeAndDelete(archive);
}
framework_logIfError(logger, status, NULL, "Failed to close and delete bundle");
return status;
}
celix_status_t bundle_closeRevisions(bundle_pt bundle) {
celix_status_t status = CELIX_SUCCESS;
// TODO implement this
return status;
}
celix_status_t bundle_closeModules(bundle_pt bundle) {
celix_status_t status = CELIX_SUCCESS;
unsigned int i = 0;
for (i = 0; i < arrayList_size(bundle->modules); i++) {
module_pt module = (module_pt) arrayList_get(bundle->modules, i);
resolver_removeModule(module);
module_setWires(module, NULL);
}
return status;
}
celix_status_t bundle_refresh(bundle_pt bundle) {
celix_status_t status;
module_pt module;
status = bundle_closeModules(bundle);
if (status == CELIX_SUCCESS) {
arrayList_clear(bundle->modules);
status = bundle_createModule(bundle, &module);
if (status == CELIX_SUCCESS) {
status = bundle_addModule(bundle, module);
if (status == CELIX_SUCCESS) {
bundle->state = OSGI_FRAMEWORK_BUNDLE_INSTALLED;
}
}
}
framework_logIfError(logger, status, NULL, "Failed to refresh bundle");
return status;
}
celix_status_t bundle_getBundleId(bundle_pt bundle, long *id) {
celix_status_t status;
bundle_archive_pt archive = NULL;
status = bundle_getArchive(bundle, &archive);
if (status == CELIX_SUCCESS) {
status = bundleArchive_getId(archive, id);
}
framework_logIfError(logger, status, NULL, "Failed to get bundle id");
return status;
}
celix_status_t bundle_getRegisteredServices(bundle_pt bundle, array_list_pt *list) {
celix_status_t status;
status = fw_getBundleRegisteredServices(bundle->framework, bundle, list);
framework_logIfError(bundle->framework->logger, status, NULL, "Failed to get registered services");
return status;
}
celix_status_t bundle_getServicesInUse(bundle_pt bundle, array_list_pt *list) {
celix_status_t status;
status = fw_getBundleServicesInUse(bundle->framework, bundle, list);
framework_logIfError(logger, status, NULL, "Failed to get in use services");
return status;
}
celix_status_t bundle_setFramework(bundle_pt bundle, framework_pt framework) {
celix_status_t status = CELIX_SUCCESS;
if (bundle != NULL && framework != NULL) {
bundle->framework = framework;
} else {
status = CELIX_ILLEGAL_ARGUMENT;
}
framework_logIfError(logger, status, NULL, "Failed to set framework");
return status;
}
celix_status_t bundle_getFramework(bundle_pt bundle, framework_pt *framework) {
celix_status_t status = CELIX_SUCCESS;
if (bundle != NULL && *framework == NULL) {
*framework = bundle->framework;
} else {
status = CELIX_ILLEGAL_ARGUMENT;
}
framework_logIfError(logger, status, NULL, "Failed to get framework");
return status;
}
celix_status_t bundle_getBundleLocation(bundle_pt bundle, const char **location){
celix_status_t status;
bundle_archive_pt archive = NULL;
status = bundle_getArchive(bundle, &archive);
if (status != CELIX_SUCCESS){
printf("[ ERROR ]: Bundle - getBundleLocation (BundleArchive) \n");
return status;
}
status = bundleArchive_getLocation(archive, location);
if (status != CELIX_SUCCESS){
printf("[ ERROR ]: Bundle - getBundleLocation (BundleArchiveLocation) \n");
return status;
}
return CELIX_SUCCESS;
}