This is an automated email from the ASF dual-hosted git repository. pnoltes pushed a commit to branch feature/query_command in repository https://gitbox.apache.org/repos/asf/celix.git
commit 59f578393047e4531afd7b53eafa624b24c6617a Author: Pepijn Noltes <[email protected]> AuthorDate: Sun Feb 2 22:16:29 2020 +0100 gh-144: Adds initial impl for the query command. Also refactors the shell impl. Adds a much needed mutex. --- bundles/shell/remote_shell/src/shell_mediator.c | 2 +- bundles/shell/shell/CMakeLists.txt | 2 + bundles/shell/shell/include/command.h | 2 +- bundles/shell/shell/include/shell.h | 31 +- bundles/shell/shell/src/activator.c | 183 +++++++----- bundles/shell/shell/src/help_command.c | 12 +- bundles/shell/shell/src/lb_command.c | 3 +- bundles/shell/shell/src/shell.c | 332 +++++++-------------- bundles/shell/shell/src/shell_private.h | 30 +- bundles/shell/shell/src/std_commands.h | 3 + bundles/shell/shell_tui/private/src/shell_tui.c | 8 +- .../shell_wui/src/shell_wui_bundle_activator.c | 2 +- libs/framework/CMakeLists.txt | 1 + libs/framework/include/celix_bundle.h | 55 ++++ libs/framework/include/service_registration.h | 4 + libs/framework/include/service_registry.h | 31 +- libs/framework/private/mock/bundle_mock.c | 20 ++ .../private/mock/service_registration_mock.c | 5 + .../framework/private/mock/service_registry_mock.c | 25 ++ libs/framework/src/bundle.c | 59 ++++ libs/framework/src/bundle_context.c | 12 +- libs/framework/src/bundle_context_private.h | 4 +- libs/framework/src/service_registration.c | 17 +- libs/framework/src/service_registry.c | 55 ++++ libs/framework/src/service_tracker.c | 35 ++- 25 files changed, 554 insertions(+), 379 deletions(-) diff --git a/bundles/shell/remote_shell/src/shell_mediator.c b/bundles/shell/remote_shell/src/shell_mediator.c index 0839be2..e12abb2 100644 --- a/bundles/shell/remote_shell/src/shell_mediator.c +++ b/bundles/shell/remote_shell/src/shell_mediator.c @@ -110,7 +110,7 @@ celix_status_t shellMediator_executeCommand(shell_mediator_pt instance, char *co if (instance->shellService != NULL) { - instance->shellService->executeCommand(instance->shellService->shell, command, out, err); + instance->shellService->executeCommand(instance->shellService->handle, command, out, err); } celixThreadMutex_unlock(&instance->mutex); diff --git a/bundles/shell/shell/CMakeLists.txt b/bundles/shell/shell/CMakeLists.txt index 4d59345..c1037b7 100644 --- a/bundles/shell/shell/CMakeLists.txt +++ b/bundles/shell/shell/CMakeLists.txt @@ -44,6 +44,8 @@ if (SHELL) src/inspect_command src/help_command src/dm_shell_list_command + src/query_command.c + src/q_command.c ) target_include_directories(shell PRIVATE src) target_link_libraries(shell PRIVATE Celix::shell_api CURL::libcurl Celix::log_service_api Celix::log_helper) diff --git a/bundles/shell/shell/include/command.h b/bundles/shell/shell/include/command.h index 3ab3f2a..df1310b 100644 --- a/bundles/shell/shell/include/command.h +++ b/bundles/shell/shell/include/command.h @@ -49,7 +49,7 @@ typedef command_service_t * command_service_pt; */ struct commandService { void *handle; - celix_status_t (*executeCommand)(void *handle, char * commandLine, FILE *outStream, FILE *errorStream); + celix_status_t (*executeCommand)(void *handle, char* commandLine, FILE *outStream, FILE *errorStream); }; diff --git a/bundles/shell/shell/include/shell.h b/bundles/shell/shell/include/shell.h index 54bc6e8..306c881 100644 --- a/bundles/shell/shell/include/shell.h +++ b/bundles/shell/shell/include/shell.h @@ -31,18 +31,31 @@ #include "service_reference.h" static const char * const OSGI_SHELL_SERVICE_NAME = "shellService"; - -typedef struct shell shell_t; -typedef shell_t* shell_pt; +static const char * const OSGI_SHELL_SERVICE_VERSION = "2.0.0"; struct shellService { - shell_pt shell; + void *handle; + + /** + * List the registered command names. Caller is owner of the commands. + * @return A celix array list with char*. + */ + celix_status_t (*getCommands)(void *handle, celix_array_list_t **commands); + + /** + * Gets the usage info for the provided command str. Caller is owner. + */ + celix_status_t (*getCommandUsage)(void *handle, const char *commandName, char **UsageStr); + + /** + * Gets the usage info for the provided command str. Caller is owner. + */ + celix_status_t (*getCommandDescription)(void *handle, const char *commandName, char **commandDescription); - celix_status_t (*getCommands)(shell_pt shell_ptr, celix_array_list_t **commands_ptr); - celix_status_t (*getCommandUsage)(shell_pt shell_ptr, char *command_name_str, char **usage_str); - celix_status_t (*getCommandDescription)(shell_pt shell_ptr, char *command_name_str, char **command_description_str); - celix_status_t (*getCommandReference)(shell_pt shell_ptr, char *command_name_str, service_reference_pt *command_reference_ptr); - celix_status_t (*executeCommand)(shell_pt shell_ptr, char * command_line_str, FILE *out, FILE *err); + /** + * Try to execute a commmand using the provided command line. + */ + celix_status_t (*executeCommand)(void *handle, const char *commandLine, FILE *out, FILE *err); }; typedef struct shellService shell_service_t; diff --git a/bundles/shell/shell/src/activator.c b/bundles/shell/shell/src/activator.c index 67c06e6..291e802 100644 --- a/bundles/shell/shell/src/activator.c +++ b/bundles/shell/shell/src/activator.c @@ -33,50 +33,51 @@ #include "service_tracker.h" #include "celix_constants.h" -#define NUMBER_OF_COMMANDS 11 +#define NUMBER_OF_COMMANDS 13 struct command { celix_status_t (*exec)(void *handle, char *commandLine, FILE *out, FILE *err); char *name; char *description; char *usage; - command_service_pt service; - properties_pt props; + command_service_t service; + celix_properties_t *props; long svcId; //used for service (un)registration }; -struct bundle_instance { - shell_service_pt shellService; - service_registration_pt registration; - service_tracker_pt tracker; +struct shell_bundle_activator { + shell_t *shell; + shell_service_t shellService; + long shellSvcId; + long trackerId; struct command std_commands[NUMBER_OF_COMMANDS]; }; -typedef struct bundle_instance *bundle_instance_pt; +typedef struct shell_bundle_activator shell_bundle_activator_t; -celix_status_t bundleActivator_create(bundle_context_pt context_ptr, void **_pptr) { +celix_status_t bundleActivator_create(celix_bundle_context_t* ctx, void **_pptr) { celix_status_t status = CELIX_SUCCESS; - bundle_instance_pt instance_ptr = NULL; + shell_bundle_activator_t* activator = NULL; - if (!_pptr || !context_ptr) { + if (!_pptr || !ctx) { status = CELIX_ENOMEM; } if (status == CELIX_SUCCESS) { - instance_ptr = (bundle_instance_pt) calloc(1, sizeof(struct bundle_instance)); - if (!instance_ptr) { + activator = calloc(1, sizeof(*activator)); + if (!activator) { status = CELIX_ENOMEM; } } if (status == CELIX_SUCCESS) { - status = shell_create(context_ptr, &instance_ptr->shellService); + activator->shell = shell_create(ctx); } if (status == CELIX_SUCCESS) { - instance_ptr->std_commands[0] = + activator->std_commands[0] = (struct command) { .exec = lbCommand_execute, .name = "lb", @@ -85,162 +86,191 @@ celix_status_t bundleActivator_create(bundle_context_pt context_ptr, void **_ppt "\nUse -l to print the bundle locations.\nUse -s to print the bundle symbolic names\nUse -u to print the bundle update location.", .usage = "lb [-l | -s | -u | -a] [group]" }; - instance_ptr->std_commands[1] = + activator->std_commands[1] = (struct command) { .exec = startCommand_execute, .name = "start", .description = "start bundle(s).", .usage = "start <id> [<id> ...]" }; - instance_ptr->std_commands[2] = + activator->std_commands[2] = (struct command) { .exec = stopCommand_execute, .name = "stop", .description = "stop bundle(s).", .usage = "stop <id> [<id> ...]" }; - instance_ptr->std_commands[3] = + activator->std_commands[3] = (struct command) { .exec = installCommand_execute, .name = "install", .description = "install bundle(s).", .usage = "install <file> [<file> ...]" }; - instance_ptr->std_commands[4] = + activator->std_commands[4] = (struct command) { .exec = uninstallCommand_execute, .name = "uninstall", .description = "uninstall bundle(s).", .usage = "uninstall <file> [<file> ...]" }; - instance_ptr->std_commands[5] = + activator->std_commands[5] = (struct command) { .exec = updateCommand_execute, .name = "update", .description = "update bundle(s).", .usage = "update <id> [<URL>]" }; - instance_ptr->std_commands[6] = + activator->std_commands[6] = (struct command) { .exec = helpCommand_execute, .name = "help", .description = "display available commands and description.", .usage = "help <command>]" }; - instance_ptr->std_commands[7] = + activator->std_commands[7] = (struct command) { .exec = logCommand_execute, .name = "log", .description = "print log.", .usage = "log" }; - instance_ptr->std_commands[8] = + activator->std_commands[8] = (struct command) { .exec = inspectCommand_execute, .name = "inspect", .description = "inspect services and components.", .usage = "inspect (service) (capability|requirement) [<id> ...]" }; - instance_ptr->std_commands[9] = + activator->std_commands[9] = (struct command) { .exec = dmListCommand_execute, .name = "dm", .description = "Gives an overview of the component managed by a dependency manager.", .usage = "dm [wtf] [f|full] [<Bundle ID> [<Bundle ID> [...]]]" }; - instance_ptr->std_commands[10] = - (struct command) { NULL, NULL, NULL, NULL, NULL, NULL, -1L }; /*marker for last element*/ + activator->std_commands[10] = + (struct command) { + .exec = queryCommand_execute, + .name = "query", + .description = "Query services. Query for registered and requested services" \ + "\nIf a query is provided, only service with a service name containing the query will be displayed." \ + "\nOr if the query is a filter. the filter will be used. If a filter is used, the optional bundle id will be ignored." + "\n\tIf the -v option is provided, also list the service properties." \ + "\n\tIf the -r option is provided, only query for requested services." \ + "\n\tIf the -p option is provided, only query for provided services.", + .usage = "ls [bundleId] [-v] [-p] [-r] [query_name ...]" + }; + activator->std_commands[11] = + (struct command) { + .exec = qCommand_execute, + .name = "q", + .description = "Quit (exit) framework.", + .usage = "q" + }; + activator->std_commands[12] = + (struct command) { NULL, NULL, NULL, NULL, {NULL,NULL}, NULL, -1L }; /*marker for last element*/ unsigned int i = 0; - while (instance_ptr->std_commands[i].exec != NULL) { - instance_ptr->std_commands[i].props = properties_create(); - if (!instance_ptr->std_commands[i].props) { + while (activator->std_commands[i].exec != NULL) { + activator->std_commands[i].props = properties_create(); + if (!activator->std_commands[i].props) { status = CELIX_BUNDLE_EXCEPTION; break; } - properties_set(instance_ptr->std_commands[i].props, OSGI_SHELL_COMMAND_NAME, instance_ptr->std_commands[i].name); - properties_set(instance_ptr->std_commands[i].props, OSGI_SHELL_COMMAND_USAGE, instance_ptr->std_commands[i].usage); - properties_set(instance_ptr->std_commands[i].props, OSGI_SHELL_COMMAND_DESCRIPTION, instance_ptr->std_commands[i].description); - properties_set(instance_ptr->std_commands[i].props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, CELIX_FRAMEWORK_SERVICE_C_LANGUAGE); + celix_properties_set(activator->std_commands[i].props, OSGI_SHELL_COMMAND_NAME, activator->std_commands[i].name); + celix_properties_set(activator->std_commands[i].props, OSGI_SHELL_COMMAND_USAGE, activator->std_commands[i].usage); + celix_properties_set(activator->std_commands[i].props, OSGI_SHELL_COMMAND_DESCRIPTION, activator->std_commands[i].description); + celix_properties_set(activator->std_commands[i].props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, CELIX_FRAMEWORK_SERVICE_C_LANGUAGE); - instance_ptr->std_commands[i].service = calloc(1, sizeof(*instance_ptr->std_commands[i].service)); - if (!instance_ptr->std_commands[i].service) { - status = CELIX_ENOMEM; - break; - } - - instance_ptr->std_commands[i].service->handle = context_ptr; - instance_ptr->std_commands[i].service->executeCommand = instance_ptr->std_commands[i].exec; + activator->std_commands[i].service.handle = ctx; + activator->std_commands[i].service.executeCommand = activator->std_commands[i].exec; i += 1; } } if (status == CELIX_SUCCESS) { - *_pptr = instance_ptr; + *_pptr = activator; } if (status != CELIX_SUCCESS) { - bundleActivator_destroy(instance_ptr, context_ptr); + bundleActivator_destroy(activator, ctx); } return status; } -celix_status_t bundleActivator_start(void *_ptr, bundle_context_pt context_ptr) { +celix_status_t bundleActivator_start(void *activatorData, celix_bundle_context_t* ctx) { celix_status_t status = CELIX_SUCCESS; - bundle_instance_pt instance_ptr = (bundle_instance_pt) _ptr; + shell_bundle_activator_t* activator = (shell_bundle_activator_t*) activatorData; - if (!instance_ptr || !context_ptr) { + if (!activator || !ctx) { status = CELIX_ILLEGAL_ARGUMENT; } if (status == CELIX_SUCCESS) { - properties_pt props = properties_create(); - properties_set(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, CELIX_FRAMEWORK_SERVICE_C_LANGUAGE); - status = bundleContext_registerService(context_ptr, (char *) OSGI_SHELL_SERVICE_NAME, instance_ptr->shellService, props, &instance_ptr->registration); + activator->shellService.handle = activator->shell; + activator->shellService.executeCommand = (void*)shell_executeCommand; + activator->shellService.getCommandDescription = (void*)shell_getCommandDescription; + activator->shellService.getCommandUsage = (void*)shell_getCommandUsage; + activator->shellService.getCommands = (void*)shell_getCommands; + + celix_service_registration_options_t opts = CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS; + opts.serviceName = OSGI_SHELL_SERVICE_NAME; + opts.serviceVersion = OSGI_SHELL_SERVICE_VERSION; + opts.svc = &activator->shellService; + + activator->shellSvcId = celix_bundleContext_registerServiceWithOptions(ctx, &opts); } if (status == CELIX_SUCCESS) { - service_tracker_customizer_pt cust = NULL; - serviceTrackerCustomizer_create(instance_ptr->shellService->shell, NULL, (void *)shell_addCommand, NULL, (void *)shell_removeCommand, &cust); - serviceTracker_create(context_ptr, (char *)OSGI_SHELL_COMMAND_SERVICE_NAME, cust, &instance_ptr->tracker); - serviceTracker_open(instance_ptr->tracker); + celix_service_tracking_options_t opts = CELIX_EMPTY_SERVICE_TRACKING_OPTIONS; + opts.callbackHandle = activator->shell; + opts.addWithProperties = (void*) shell_addCommand; + opts.removeWithProperties = (void*) shell_removeCommand; + opts.filter.ignoreServiceLanguage = true; + opts.filter.serviceName = OSGI_SHELL_COMMAND_SERVICE_NAME; + activator->trackerId = celix_bundleContext_trackServicesWithOptions(ctx, &opts); } if (status == CELIX_SUCCESS) { - for (unsigned int i = 0; instance_ptr->std_commands[i].exec != NULL; i++) { + for (unsigned int i = 0; activator->std_commands[i].exec != NULL; i++) { celix_service_registration_options_t opts = CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS; - opts.svc = instance_ptr->std_commands[i].service; + opts.svc = &activator->std_commands[i].service; opts.serviceName = OSGI_SHELL_COMMAND_SERVICE_NAME; opts.serviceVersion = OSGI_SHELL_COMMAND_SERVICE_VERSION; - opts.properties = instance_ptr->std_commands[i].props; - instance_ptr->std_commands[i].svcId = celix_bundleContext_registerServiceWithOptions(context_ptr, &opts); + opts.properties = activator->std_commands[i].props; + activator->std_commands[i].svcId = celix_bundleContext_registerServiceWithOptions(ctx, &opts); } } return status; } -celix_status_t bundleActivator_stop(void *_ptr, bundle_context_pt context_ptr) { +celix_status_t bundleActivator_stop(void *activatorData, celix_bundle_context_t* ctx) { celix_status_t status = CELIX_SUCCESS; - bundle_instance_pt instance_ptr = (bundle_instance_pt) _ptr; + shell_bundle_activator_t* activator = activatorData; - if (instance_ptr) { - for (unsigned int i = 0; instance_ptr->std_commands[i].exec != NULL; i++) { - if (instance_ptr->std_commands[i].svcId >= 0) { - celix_bundleContext_unregisterService(context_ptr, instance_ptr->std_commands[i].svcId); - instance_ptr->std_commands[i].props = NULL; + if (activator) { + for (unsigned int i = 0; activator->std_commands[i].exec != NULL; i++) { + if (activator->std_commands[i].svcId >= 0) { + celix_bundleContext_unregisterService(ctx, activator->std_commands[i].svcId); + activator->std_commands[i].props = NULL; } } - if (instance_ptr->tracker != NULL) { - serviceTracker_close(instance_ptr->tracker); + if (activator->shellSvcId >= 0L) { + celix_bundleContext_unregisterService(ctx, activator->shellSvcId); + } + + if (activator->trackerId >= 0L) { + celix_bundleContext_stopTracker(ctx, activator->trackerId); } } else { status = CELIX_ILLEGAL_ARGUMENT; @@ -249,25 +279,14 @@ celix_status_t bundleActivator_stop(void *_ptr, bundle_context_pt context_ptr) { return status; } -celix_status_t bundleActivator_destroy(void *_ptr, bundle_context_pt __attribute__((__unused__)) context_ptr) { +celix_status_t bundleActivator_destroy(void *activatorData, celix_bundle_context_t* __attribute__((__unused__)) ctx) { celix_status_t status = CELIX_SUCCESS; + shell_bundle_activator_t* activator = activatorData; - bundle_instance_pt instance_ptr = (bundle_instance_pt) _ptr; - - if (instance_ptr) { - serviceRegistration_unregister(instance_ptr->registration); - - for (unsigned int i = 0; instance_ptr->std_commands[i].exec != NULL; i++) { - free(instance_ptr->std_commands[i].service); - } - - shell_destroy(&instance_ptr->shellService); - - if (instance_ptr->tracker != NULL) { - serviceTracker_destroy(instance_ptr->tracker); - } - free(instance_ptr); + if (activator) { + shell_destroy(activator->shell); + free(activator); } else { status = CELIX_ILLEGAL_ARGUMENT; } diff --git a/bundles/shell/shell/src/help_command.c b/bundles/shell/shell/src/help_command.c index 1c29ab2..91550cc 100644 --- a/bundles/shell/shell/src/help_command.c +++ b/bundles/shell/shell/src/help_command.c @@ -52,7 +52,7 @@ static void printHelp(void *handle, void *svc) { unsigned int i; array_list_pt commands = NULL; - shell->getCommands(shell->shell, &commands); + shell->getCommands(shell->handle, &commands); for (i = 0; i < arrayList_size(commands); i++) { char *name = arrayList_get(commands, i); fprintf(out, "%s\n", name); @@ -64,15 +64,15 @@ static void printHelp(void *handle, void *svc) { celix_status_t sub_status_usage; int i; celix_array_list_t *commands = NULL; - shell->getCommands(shell->shell, &commands); + shell->getCommands(shell->handle, &commands); for (i = 0; i < arrayList_size(commands); i++) { char *name = arrayList_get(commands, i); if (strcmp(sub, name) == 0) { char *usage_str = NULL; char *desc_str = NULL; - sub_status_desc = shell->getCommandDescription(shell->shell, name, &desc_str); - sub_status_usage = shell->getCommandUsage(shell->shell, name, &usage_str); + sub_status_desc = shell->getCommandDescription(shell->handle, name, &desc_str); + sub_status_usage = shell->getCommandUsage(shell->handle, name, &usage_str); if (sub_status_usage == CELIX_SUCCESS && sub_status_desc == CELIX_SUCCESS) { fprintf(out, "Command : %s\n", name); @@ -81,7 +81,11 @@ static void printHelp(void *handle, void *svc) { } else { fprintf(err, "Error retrieving help info for command '%s'\n", sub); } + + free(usage_str); + free(desc_str); } + free(name); } celix_arrayList_destroy(commands); } diff --git a/bundles/shell/shell/src/lb_command.c b/bundles/shell/shell/src/lb_command.c index ffeb9ce..8734a6c 100644 --- a/bundles/shell/shell/src/lb_command.c +++ b/bundles/shell/shell/src/lb_command.c @@ -264,8 +264,7 @@ celix_status_t lbCommand_execute(void *_ptr, char *command_line_str, FILE *out_p lb_options_t opts; memset(&opts, 0, sizeof(opts)); - const char* config = NULL; - bundleContext_getPropertyWithDefault(ctx, SHELL_USE_ANSI_COLORS, SHELL_USE_ANSI_COLORS_DEFAULT_VALUE, &config); + const char* config = celix_bundleContext_getProperty(ctx, SHELL_USE_ANSI_COLORS, SHELL_USE_ANSI_COLORS_DEFAULT_VALUE); opts.useColors = config != NULL && strncmp("true", config, 5) == 0; diff --git a/bundles/shell/shell/src/shell.c b/bundles/shell/shell/src/shell.c index ce90108..bc67700 100644 --- a/bundles/shell/shell/src/shell.c +++ b/bundles/shell/shell/src/shell.c @@ -16,17 +16,12 @@ * specific language governing permissions and limitations * under the License. */ -/** - * shell.c - * - * \date Aug 13, 2010 - * \author <a href="mailto:[email protected]">Apache Celix Project Team</a> - * \copyright Apache License, Version 2.0 - */ + #include <stdlib.h> #include <string.h> #include <log_helper.h> +#include <celix_constants.h> #include "celix_errno.h" @@ -35,271 +30,154 @@ #include "utils.h" -celix_status_t shell_getCommands(shell_pt shell_ptr, array_list_pt *commands_ptr); -celix_status_t shell_getCommandUsage(shell_pt shell_ptr, char *command_name_str, char **usage_pstr); -celix_status_t shell_getCommandDescription(shell_pt shell_ptr, char *command_name_str, char **command_description_pstr); -celix_status_t shell_create(bundle_context_pt context_ptr, shell_service_pt *shell_service_ptr) { - celix_status_t status = CELIX_SUCCESS; +shell_t* shell_create(celix_bundle_context_t *ctx) { + shell_t *shell = calloc(1, sizeof(*shell)); - if (!context_ptr || !shell_service_ptr) { - status = CELIX_ILLEGAL_ARGUMENT; - } - - if (status == CELIX_SUCCESS) { - *shell_service_ptr = calloc(1, sizeof(**shell_service_ptr)); - if (!*shell_service_ptr) { - status = CELIX_ENOMEM; - } - } - - if (status == CELIX_SUCCESS) { - (*shell_service_ptr)->shell = calloc(1, sizeof(*(*shell_service_ptr)->shell)); - if (!(*shell_service_ptr)->shell) { - status = CELIX_ENOMEM; - } - } - - if (status == CELIX_SUCCESS) { - (*shell_service_ptr)->shell->bundle_context_ptr = context_ptr; - (*shell_service_ptr)->shell->command_name_map_ptr = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL); - (*shell_service_ptr)->shell->command_reference_map_ptr = hashMap_create(NULL, NULL, NULL, NULL); + shell->ctx = ctx; + logHelper_create(ctx, &shell->logHelper); - (*shell_service_ptr)->getCommands = shell_getCommands; - (*shell_service_ptr)->getCommandDescription = shell_getCommandDescription; - (*shell_service_ptr)->getCommandUsage = shell_getCommandUsage; - (*shell_service_ptr)->getCommandReference = shell_getCommandReference; - (*shell_service_ptr)->executeCommand = shell_executeCommand; + celix_thread_mutexattr_t attr; + celixThreadMutexAttr_create(&attr); + celixThreadMutexAttr_settype(&attr, CELIX_THREAD_MUTEX_RECURSIVE); //NOTE recursive, because command can also use the shell service + celixThreadMutex_create(&shell->mutex, &attr); + shell->commandServices = hashMap_create(utils_stringHash, NULL, utils_stringEquals, NULL); - status = logHelper_create(context_ptr, &(*shell_service_ptr)->shell->logHelper); - } - - if (status != CELIX_SUCCESS) { - shell_destroy(shell_service_ptr); - } - - return status; + return shell; } -celix_status_t shell_destroy(shell_service_pt *shell_service_ptr) { - celix_status_t status = CELIX_SUCCESS; - - if (!shell_service_ptr || !*shell_service_ptr) { - status = CELIX_ILLEGAL_ARGUMENT; - } - - if (status == CELIX_SUCCESS) { - if ((*shell_service_ptr)->shell) { - if ((*shell_service_ptr)->shell->command_name_map_ptr) { - hashMap_destroy((*shell_service_ptr)->shell->command_name_map_ptr, false, false); - } - if ((*shell_service_ptr)->shell->command_reference_map_ptr) { - hashMap_destroy((*shell_service_ptr)->shell->command_reference_map_ptr, false, false); - } - if ((*shell_service_ptr)->shell->logHelper) { - logHelper_destroy(&((*shell_service_ptr)->shell->logHelper)); - } - free((*shell_service_ptr)->shell); - (*shell_service_ptr)->shell = NULL; - } - free(*shell_service_ptr); - *shell_service_ptr = NULL; - } - - return status; +void shell_destroy(shell_t *shell) { + if (shell != NULL) { + celixThreadMutex_destroy(&shell->mutex); + hashMap_destroy(shell->commandServices, false, false); + logHelper_destroy(&shell->logHelper); + free(shell); + } } -celix_status_t shell_addCommand(shell_pt shell_ptr, service_reference_pt reference_ptr, void *svc) { +celix_status_t shell_addCommand(shell_t *shell, command_service_t *svc, const celix_properties_t *props) { celix_status_t status = CELIX_SUCCESS; - command_service_pt command_ptr = NULL; - const char *name_str = NULL; - - if (!shell_ptr || !reference_ptr) { - return CELIX_ILLEGAL_ARGUMENT; - } - - if (status == CELIX_SUCCESS) { - command_ptr = svc; - } - - if (status == CELIX_SUCCESS) { - status = serviceReference_getProperty(reference_ptr, "command.name", &name_str); - if (!name_str) { - logHelper_log(shell_ptr->logHelper, OSGI_LOGSERVICE_ERROR, "Command service must contain a 'command.name' property!"); - status = CELIX_BUNDLE_EXCEPTION; + const char *name = celix_properties_get(props, "command.name", NULL); + + if (name == NULL) { + logHelper_log(shell->logHelper, OSGI_LOGSERVICE_WARNING, "Command service must contain a 'command.name' property!"); + status = CELIX_BUNDLE_EXCEPTION; + } else { + long svcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, -1L); + celixThreadMutex_lock(&shell->mutex); + if (hashMap_containsKey(shell->commandServices, name)) { + logHelper_log(shell->logHelper, OSGI_LOGSERVICE_WARNING, "Command with name %s already registered!", name); + } else { + celix_shell_command_entry_t *entry = calloc(1, sizeof(*entry)); + entry->svcId = svcId; + entry->svc = svc; + entry->props = props; + hashMap_put(shell->commandServices, (void*)name, entry); } - } - - if (status == CELIX_SUCCESS) { - hashMap_put(shell_ptr->command_name_map_ptr, (char *)name_str, command_ptr); - hashMap_put(shell_ptr->command_reference_map_ptr, reference_ptr, command_ptr); - } - - if (status != CELIX_SUCCESS) { - shell_removeCommand(shell_ptr, reference_ptr, svc); - char err[32]; - celix_strerror(status, err, 32); - logHelper_log(shell_ptr->logHelper, OSGI_LOGSERVICE_ERROR, "Could not add command, got error %s\n", err); + celixThreadMutex_unlock(&shell->mutex); } return status; } -celix_status_t shell_removeCommand(shell_pt shell_ptr, service_reference_pt reference_ptr, void *svc) { +celix_status_t shell_removeCommand(shell_t *shell, command_service_t *svc, const celix_properties_t *props) { celix_status_t status = CELIX_SUCCESS; - - command_service_pt command_ptr = NULL; - const char *name_str = NULL; - - if (!shell_ptr || !reference_ptr) { - status = CELIX_ILLEGAL_ARGUMENT; - } - - if (status == CELIX_SUCCESS) { - command_ptr = hashMap_remove(shell_ptr->command_reference_map_ptr, reference_ptr); - if (!command_ptr) { - status = CELIX_ILLEGAL_ARGUMENT; - } - } - - if (status == CELIX_SUCCESS) { - status = serviceReference_getProperty(reference_ptr, "command.name", &name_str); - if (!name_str) { - status = CELIX_BUNDLE_EXCEPTION; + const char *name = celix_properties_get(props, "command.name", NULL); + + if (name == NULL) { + logHelper_log(shell->logHelper, OSGI_LOGSERVICE_WARNING, "Command service must contain a 'command.name' property!"); + status = CELIX_BUNDLE_EXCEPTION; + } else { + long svcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, -1L); + celixThreadMutex_lock(&shell->mutex); + if (hashMap_containsKey(shell->commandServices, name)) { + celix_shell_command_entry_t *entry = hashMap_get(shell->commandServices, name); + if (entry->svcId == svcId) { + hashMap_remove(shell->commandServices, name); + free(entry); + } else { + logHelper_log(shell->logHelper, OSGI_LOGSERVICE_WARNING, "svc id for command with name %s does not match (%li == %li)!", name, svcId, entry->svcId); + } + } else { + logHelper_log(shell->logHelper, OSGI_LOGSERVICE_WARNING, "Cannot find shell command with name %s!", name); } - } - - if (status == CELIX_SUCCESS) { - hashMap_remove(shell_ptr->command_name_map_ptr, (char *)name_str); + celixThreadMutex_unlock(&shell->mutex); } return status; } -celix_status_t shell_getCommands(shell_pt shell_ptr, array_list_pt *commands_ptr) { +celix_status_t shell_getCommands(shell_t *shell, celix_array_list_t **outCommands) { celix_status_t status = CELIX_SUCCESS; + celix_array_list_t *result = celix_arrayList_create(); - hash_map_iterator_pt iter = NULL; - - if (!shell_ptr || !commands_ptr) { - status = CELIX_ILLEGAL_ARGUMENT; - } - - if (status == CELIX_SUCCESS) { - iter = hashMapIterator_create(shell_ptr->command_name_map_ptr); - if (!iter) { - status = CELIX_BUNDLE_EXCEPTION; - } - } + celixThreadMutex_lock(&shell->mutex); + hash_map_iterator_t iter = hashMapIterator_construct(shell->commandServices); + while (hashMapIterator_hasNext(&iter)) { + const char *name = hashMapIterator_nextKey(&iter); + celix_arrayList_add(result, strndup(name, 1024*1024*10)); + } + celixThreadMutex_unlock(&shell->mutex); - if (status == CELIX_SUCCESS) { - arrayList_create(commands_ptr); - while (hashMapIterator_hasNext(iter)) { - char *name_str = hashMapIterator_nextKey(iter); - arrayList_add(*commands_ptr, name_str); - } - hashMapIterator_destroy(iter); - } + *outCommands = result; - return status; + return status; } -celix_status_t shell_getCommandUsage(shell_pt shell_ptr, char *command_name_str, char **usage_pstr) { - celix_status_t status = CELIX_SUCCESS; - - service_reference_pt reference = NULL; - - if (!shell_ptr || !command_name_str || !usage_pstr) { - status = CELIX_ILLEGAL_ARGUMENT; - } +celix_status_t shell_getCommandUsage(shell_t *shell, const char *commandName, char **outUsage) { + celix_status_t status = CELIX_SUCCESS; - if (status == CELIX_SUCCESS) { - status = shell_getCommandReference(shell_ptr, command_name_str, &reference); - if (!reference) { - status = CELIX_BUNDLE_EXCEPTION; - } - } + celixThreadMutex_lock(&shell->mutex); + celix_shell_command_entry_t *entry = hashMap_get(shell->commandServices, commandName); + if (entry != NULL) { + const char *usage = celix_properties_get(entry->props, OSGI_SHELL_COMMAND_USAGE, "N/A"); + *outUsage = strndup(usage, 1024*1024*10); + } else { + *outUsage = NULL; + } + celixThreadMutex_unlock(&shell->mutex); - if (status == CELIX_SUCCESS) { - status = serviceReference_getProperty(reference, "command.usage", (const char**)usage_pstr); - } - return status; + return status; } -celix_status_t shell_getCommandDescription(shell_pt shell_ptr, char *command_name_str, char **command_description_pstr) { - celix_status_t status = CELIX_SUCCESS; - - service_reference_pt reference = NULL; - - if (!shell_ptr || !command_name_str || !command_description_pstr) { - status = CELIX_ILLEGAL_ARGUMENT; - } - - if (status == CELIX_SUCCESS) { - status = shell_getCommandReference(shell_ptr, command_name_str, &reference); - if (!reference) { - status = CELIX_BUNDLE_EXCEPTION; - } - } +celix_status_t shell_getCommandDescription(shell_t *shell, const char *commandName, char **outDescription) { + celix_status_t status = CELIX_SUCCESS; - if (status == CELIX_SUCCESS) { - serviceReference_getProperty(reference, "command.description", (const char**)command_description_pstr); - } + celixThreadMutex_lock(&shell->mutex); + celix_shell_command_entry_t *entry = hashMap_get(shell->commandServices, commandName); + if (entry != NULL) { + const char *desc = celix_properties_get(entry->props, OSGI_SHELL_COMMAND_DESCRIPTION, "N/A"); + *outDescription = strndup(desc, 1024*1024*10); + } else { + *outDescription = NULL; + } + celixThreadMutex_unlock(&shell->mutex); - return status; + return status; } -celix_status_t shell_getCommandReference(shell_pt shell_ptr, char *command_name_str, service_reference_pt *command_reference_ptr) { +celix_status_t shell_executeCommand(shell_t *shell, const char *commandLine, FILE *out, FILE *err) { celix_status_t status = CELIX_SUCCESS; - if (!shell_ptr || !command_name_str || !command_reference_ptr) { - status = CELIX_ILLEGAL_ARGUMENT; - } - if (status == CELIX_SUCCESS) { - *command_reference_ptr = NULL; - hash_map_iterator_pt iter = hashMapIterator_create(shell_ptr->command_reference_map_ptr); - while (hashMapIterator_hasNext(iter)) { - hash_map_entry_pt entry = hashMapIterator_nextEntry(iter); - service_reference_pt reference = hashMapEntry_getKey(entry); - const char *name_str = NULL; - serviceReference_getProperty(reference, "command.name", &name_str); - if (strcmp(name_str, command_name_str) == 0) { - *command_reference_ptr = (service_reference_pt) hashMapEntry_getKey(entry); - break; - } - } - hashMapIterator_destroy(iter); - } - - return status; -} - -celix_status_t shell_executeCommand(shell_pt shell_ptr, char *command_line_str, FILE *out, FILE *err) { - celix_status_t status = CELIX_SUCCESS; - - command_service_pt command_ptr = NULL; - - if (!shell_ptr || !command_line_str || !out || !err) { - status = CELIX_ILLEGAL_ARGUMENT; - } + size_t pos = strcspn(commandLine, " "); - if (status == CELIX_SUCCESS) { - size_t pos = strcspn(command_line_str, " "); + char *command_name_str = (pos != strlen(commandLine)) ? strndup(commandLine, pos) : strdup(commandLine); - char *command_name_str = (pos != strlen(command_line_str)) ? strndup(command_line_str, pos) : strdup(command_line_str); - command_ptr = hashMap_get(shell_ptr->command_name_map_ptr, command_name_str); + celixThreadMutex_lock(&shell->mutex); + celix_shell_command_entry_t *entry = hashMap_get(shell->commandServices, command_name_str); + if (entry == NULL) { + fprintf(err, "No such command\n"); + status = CELIX_BUNDLE_EXCEPTION; + } else { + char * cl = (void*)commandLine; //NOTE needed because the shell command was written with char* instead of const char* + entry->svc->executeCommand(entry->svc->handle, cl, out, err); + } + celixThreadMutex_unlock(&shell->mutex); free(command_name_str); - if (!command_ptr) { - fprintf(err, "No such command\n"); - status = CELIX_BUNDLE_EXCEPTION; - } - } - if (status == CELIX_SUCCESS) { - status = command_ptr->executeCommand(command_ptr->handle, command_line_str, out, err); } return status; diff --git a/bundles/shell/shell/src/shell_private.h b/bundles/shell/shell/src/shell_private.h index c056bbd..b845ef1 100644 --- a/bundles/shell/shell/src/shell_private.h +++ b/bundles/shell/shell/src/shell_private.h @@ -33,19 +33,29 @@ #include "command.h" #include "log_helper.h" +typedef struct celix_shell_command_entry { + long svcId; + command_service_t *svc; + const celix_properties_t *props; +} celix_shell_command_entry_t; + struct shell { - bundle_context_pt bundle_context_ptr; - hash_map_pt command_reference_map_ptr; - hash_map_pt command_name_map_ptr; - log_helper_t *logHelper; + celix_bundle_context_t *ctx; + log_helper_t *logHelper; + celix_thread_mutex_t mutex; //protects below + hash_map_t *commandServices; //key = char* (command name), value = celix_shell_command_entry_t* }; +typedef struct shell shell_t; + +shell_t* shell_create(celix_bundle_context_t *ctx); +void shell_destroy(shell_t *shell); +celix_status_t shell_addCommand(shell_t *shell, command_service_t *svc, const celix_properties_t *props); +celix_status_t shell_removeCommand(shell_t *shell, command_service_t *svc, const celix_properties_t *props); -celix_status_t shell_create(bundle_context_pt context_ptr, shell_service_pt *shell_service_ptr); -celix_status_t shell_destroy(shell_service_pt *shell_service_ptr); -celix_status_t shell_addCommand(shell_pt shell_ptr, service_reference_pt reference_ptr, void *svc); -celix_status_t shell_removeCommand(shell_pt shell_ptr, service_reference_pt reference_ptr, void *svc); +celix_status_t shell_executeCommand(shell_t *shell, const char *commandLine, FILE *out, FILE *err); -celix_status_t shell_getCommandReference(shell_pt shell_ptr, char *command_name_str, service_reference_pt *command_reference_ptr); -celix_status_t shell_executeCommand(shell_pt shell_ptr, char *command_line_str, FILE *out, FILE *err); +celix_status_t shell_getCommands(shell_t *shell, celix_array_list_t **commands); +celix_status_t shell_getCommandUsage(shell_t *shell, const char *commandName, char **outUsage); +celix_status_t shell_getCommandDescription(shell_t *shell, const char *commandName, char **outDescription); #endif /* SHELL_PRIVATE_H_ */ diff --git a/bundles/shell/shell/src/std_commands.h b/bundles/shell/shell/src/std_commands.h index a0c66b4..ef15f93 100644 --- a/bundles/shell/shell/src/std_commands.h +++ b/bundles/shell/shell/src/std_commands.h @@ -31,7 +31,9 @@ #define OSGI_SHELL_COMMAND_SEPARATOR " " +//TODO update all char *command_line_str to const char *command_line_str celix_status_t lbCommand_execute(void *_ptr, char *command_line_str, FILE *out_ptr, FILE *err_ptr); +celix_status_t queryCommand_execute(void *_ptr, char *command_line_str, FILE *out_ptr, FILE *err_ptr); celix_status_t startCommand_execute(void *_ptr, char* command_line_str, FILE *out_ptr, FILE *err_ptr); celix_status_t stopCommand_execute(void *handle, char* commandline, FILE *outStream, FILE *errStream); celix_status_t installCommand_execute(void *handle, char * commandline, FILE *outStream, FILE *errStream); @@ -41,6 +43,7 @@ celix_status_t logCommand_execute(void *handle, char * commandline, FILE *outStr celix_status_t inspectCommand_execute(void *handle, char * commandline, FILE *outStream, FILE *errStream); celix_status_t helpCommand_execute(void *handle, char * commandline, FILE *outStream, FILE *errStream); celix_status_t dmListCommand_execute(void* handle, char * line, FILE *out, FILE *err); +celix_status_t qCommand_execute(void *_ptr, char *command_line_str, FILE *sout, FILE *serr); #endif diff --git a/bundles/shell/shell_tui/private/src/shell_tui.c b/bundles/shell/shell_tui/private/src/shell_tui.c index bbb443d..57bd6d8 100644 --- a/bundles/shell/shell_tui/private/src/shell_tui.c +++ b/bundles/shell/shell_tui/private/src/shell_tui.c @@ -256,7 +256,7 @@ static void shellTui_parseInput(shell_tui_t* shellTui, shell_context_t* ctx) { celixThreadMutex_lock(&shellTui->mutex); if (shellTui->shell != NULL) { printf("Providing command '%s' from in '%s'\n", line, in); - shellTui->shell->executeCommand(shellTui->shell->shell, line, stdout, stderr); + shellTui->shell->executeCommand(shellTui->shell->handle, line, stdout, stderr); } else { fprintf(stderr, "Shell service not available\n"); } @@ -379,7 +379,7 @@ static void shellTui_parseInputForControl(shell_tui_t* shellTui, shell_context_t historyLineReset(hist); celixThreadMutex_lock(&shellTui->mutex); if (shellTui->shell != NULL) { - shellTui->shell->executeCommand(shellTui->shell->shell, line, stdout, stderr); + shellTui->shell->executeCommand(shellTui->shell->handle, line, stdout, stderr); pos = 0; nr_chars = 0; } else { @@ -426,7 +426,7 @@ static void writeLine(const char* line, int pos) { static int autoComplete(shell_service_t* shellSvc, char *in, int cursorPos, size_t maxLen) { array_list_pt commandList = NULL; array_list_pt possibleCmdList = NULL; - shellSvc->getCommands(shellSvc->shell, &commandList); + shellSvc->getCommands(shellSvc->handle, &commandList); int nrCmds = arrayList_size(commandList); arrayList_create(&possibleCmdList); @@ -446,7 +446,7 @@ static int autoComplete(shell_service_t* shellSvc, char *in, int cursorPos, size if (strncmp(in, cmd, strlen(cmd)) == 0) { clearLine(); char* usage = NULL; - shellSvc->getCommandUsage(shellSvc->shell, cmd, &usage); + shellSvc->getCommandUsage(shellSvc->handle, cmd, &usage); printf("Usage:\n %s\n", usage); } } diff --git a/bundles/shell/shell_wui/src/shell_wui_bundle_activator.c b/bundles/shell/shell_wui/src/shell_wui_bundle_activator.c index 932509b..72d0f90 100644 --- a/bundles/shell/shell_wui/src/shell_wui_bundle_activator.c +++ b/bundles/shell/shell_wui/src/shell_wui_bundle_activator.c @@ -44,7 +44,7 @@ static void useShell(void *handle, void *svc) { char *buf = NULL; size_t size; FILE *out = open_memstream(&buf, &size); - shell->executeCommand(shell->shell, arg->command, out, out); + shell->executeCommand(shell->handle, arg->command, out, out); fclose(out); mg_websocket_write(arg->conn, MG_WEBSOCKET_OPCODE_TEXT, buf, size); }; diff --git a/libs/framework/CMakeLists.txt b/libs/framework/CMakeLists.txt index 1946eb8..0ad8364 100644 --- a/libs/framework/CMakeLists.txt +++ b/libs/framework/CMakeLists.txt @@ -131,6 +131,7 @@ if (ENABLE_TESTING AND FRAMEWORK_TESTS) private/mock/bundle_revision_mock.c private/mock/resolver_mock.c private/mock/version_mock.c + private/mock/service_registry_mock.c src/bundle.c src/celix_errorcodes.c private/mock/celix_log_mock.c) diff --git a/libs/framework/include/celix_bundle.h b/libs/framework/include/celix_bundle.h index bd12693..0b0dac4 100644 --- a/libs/framework/include/celix_bundle.h +++ b/libs/framework/include/celix_bundle.h @@ -54,11 +54,66 @@ celix_bundle_state_e celix_bundle_getState(const celix_bundle_t *bnd); */ char* celix_bundle_getEntry(const celix_bundle_t* bnd, const char *path); +/** + * Returns the group of the bundle. Groups are used to order bundles. + * Note the return value is valid as long as the bundle is installed. + */ const char* celix_bundle_getGroup(const celix_bundle_t *bnd); +/** + * Returns the symbolic name of the bundle. + * Note the return value is valid as long as the bundle is installed. + */ const char* celix_bundle_getSymbolicName(const celix_bundle_t *bnd); +typedef struct celix_bundle_service_list_entry { + long serviceId; + long bundleOwner; + char *serviceName; + celix_properties_t *serviceProperties; + bool factory; +} celix_bundle_service_list_entry_t; + +/** + * Returns a array list of registered service info entries for this bundle. + * + * @param ctx The bundle context + * @param bndId The bundle id for which the services should be listed + * @return A celix array list with celix_bundle_service_list_entry_t*. Caller is owner of the celix array. + */ +celix_array_list_t* celix_bundle_listRegisteredServices(const celix_bundle_t *bnd); + +/** + * Utils function to free memory for the return of a celix_bundle_listRegisteredServices call. + */ +void celix_bundle_destroyRegisteredServicesList(celix_array_list_t* list); + + +/** + * Service Tracker Info provided to the service tracker tracker callbacks. + */ +typedef struct celix_bundle_service_tracker_list_entry { + char* filter;; + long bundleOwner; +} celix_bundle_service_tracker_list_entry_t; + + +/** + * Returns a array list of service tracker info entries for this bundle. + * + * @param ctx The bundle context + * @param bndId The bundle id for which the services should be listed + * @return A celix array list with celix_bundle_service_tracker_list_entry_t*. Caller is owner of the celix array. + */ +celix_array_list_t* celix_bundle_listServiceTrackers(const celix_bundle_t *bnd); + +/** + * Utils function to free memory for the return of a celix_bundle_listServiceTrackers call. + */ +void celix_bundle_destroyServiceTrackerList(celix_array_list_t* list); + + #ifdef __cplusplus } #endif diff --git a/libs/framework/include/service_registration.h b/libs/framework/include/service_registration.h index 097001f..4a93ae9 100644 --- a/libs/framework/include/service_registration.h +++ b/libs/framework/include/service_registration.h @@ -48,6 +48,10 @@ serviceRegistration_getServiceName(service_registration_t *registration, const c FRAMEWORK_EXPORT long serviceRegistration_getServiceId(service_registration_t *registration); +FRAMEWORK_EXPORT bool +serviceRegistration_isFactoryService(service_registration_t *registration); + + #ifdef __cplusplus } #endif diff --git a/libs/framework/include/service_registry.h b/libs/framework/include/service_registry.h index 3373328..9f06f8a 100644 --- a/libs/framework/include/service_registry.h +++ b/libs/framework/include/service_registry.h @@ -16,13 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -/** - * service_registry.h - * - * \date Aug 6, 2010 - * \author <a href="mailto:[email protected]">Apache Celix Project Team</a> - * \copyright Apache License, Version 2.0 - */ + #ifndef SERVICE_REGISTRY_H_ #define SERVICE_REGISTRY_H_ @@ -110,6 +104,29 @@ celix_serviceRegistry_registerServiceFactory( celix_properties_t* props, service_registration_t **registration); +/** + * List the registered service for the provided bundle. + * @return A list of service ids. Caller is owner of the array list. + */ +celix_array_list_t* celix_serviceRegistry_listServiceIdsForOwner(celix_service_registry_t* registry, long bndId); + +/** + * Get service information for the provided svc id and bnd id. + * + * If the output pointers for serviceName and/or serviceProperties are provided these will get a copy of the registry + * value. The caller is owner of the serviceName/serviceProperties. + * + * Returns true if the bundle is found. + */ +bool celix_serviceRegistry_getServiceInfo( + celix_service_registry_t* registry, + long svcId, + long bndId, + char **serviceName, + celix_properties_t **serviceProperties, + bool *factory); + + #ifdef __cplusplus } #endif diff --git a/libs/framework/private/mock/bundle_mock.c b/libs/framework/private/mock/bundle_mock.c index 22bd18b..86382a4 100644 --- a/libs/framework/private/mock/bundle_mock.c +++ b/libs/framework/private/mock/bundle_mock.c @@ -297,5 +297,25 @@ celix_bundle_state_e celix_bundle_getState(const bundle_t *bnd) { return (celix_bundle_state_e)mock_c()->returnValue().value.intValue; } +celix_array_list_t* celix_bundle_listRegisteredServices(const celix_bundle_t *bnd) { + mock_c()->actualCall("celix_bundle_listRegisteredServices") + ->withConstPointerParameters("bnd", bnd); + return mock_c()->returnValue().value.pointerValue; +} + +void celix_bundle_destroyRegisteredServicesList(celix_array_list_t* list) { + mock_c()->actualCall("celix_bundle_destroyRegisteredServicesList") + ->withPointerParameters("list)", list); +} +celix_array_list_t* celix_bundle_listServiceTrackers(const celix_bundle_t *bnd) { + mock_c()->actualCall("celix_bundle_listServiceTrackers") + ->withConstPointerParameters("bnd", bnd); + return mock_c()->returnValue().value.pointerValue; +} + +void celix_bundle_destroyServiceTrackerList(celix_array_list_t* list) { + mock_c()->actualCall("celix_bundle_destroyServiceTrackerList") + ->withPointerParameters("list", list); +} diff --git a/libs/framework/private/mock/service_registration_mock.c b/libs/framework/private/mock/service_registration_mock.c index 8f141eb..02715ab 100644 --- a/libs/framework/private/mock/service_registration_mock.c +++ b/libs/framework/private/mock/service_registration_mock.c @@ -157,3 +157,8 @@ service_registration_t* celix_serviceRegistration_createServiceFactory( return mock_c()->returnValue().value.pointerValue; } +bool serviceRegistration_isFactoryService(service_registration_t *registration) { + mock_c()->actualCall("serviceRegistration_isFactoryService") + ->withPointerParameters("registration", registration); + return mock_c()->returnValue().value.boolValue; +} diff --git a/libs/framework/private/mock/service_registry_mock.c b/libs/framework/private/mock/service_registry_mock.c index feb7f4a..767e507 100644 --- a/libs/framework/private/mock/service_registry_mock.c +++ b/libs/framework/private/mock/service_registry_mock.c @@ -24,6 +24,7 @@ * \copyright Apache License, Version 2.0 */ +#include <CppUTestExt/MockSupport_c.h> #include "CppUTestExt/MockSupport_c.h" #include "service_registry.h" @@ -195,3 +196,27 @@ void serviceRegistry_callHooksForListenerFilter( ->withStringParameters("filter", filter) ->withBoolParameters("removed", removed); } + +bool celix_serviceRegistry_getServiceInfo( + celix_service_registry_t* registry, + long svcId, + long bndId, + char **outServiceName, + celix_properties_t **outServiceProperties, + bool *outIsFactory) { + mock_c()->actualCall("celix_serviceRegistry_getServiceInfo") + ->withPointerParameters("registry", registry) + ->withLongIntParameters("svcId", svcId) + ->withLongIntParameters("bndId", bndId) + ->withOutputParameter("outServiceName", outServiceName) + ->withOutputParameter("outServiceProperties", outServiceProperties) + ->withOutputParameter("outIsFactory", outIsFactory); + return mock_c()->returnValue().value.boolValue; +} + +celix_array_list_t* celix_serviceRegistry_listServiceIdsForOwner(celix_service_registry_t* registry, long bndId) { + mock_c()->actualCall("celix_serviceRegistry_listServiceIdsForOwner") + ->withPointerParameters("registry", registry) + ->withLongIntParameters("bndId", bndId); + return mock_c()->returnValue().value.pointerValue; +} \ No newline at end of file diff --git a/libs/framework/src/bundle.c b/libs/framework/src/bundle.c index 251941e..89ac70d 100644 --- a/libs/framework/src/bundle.c +++ b/libs/framework/src/bundle.c @@ -19,12 +19,16 @@ #include <stdlib.h> #include <string.h> +#include <service_tracker.h> #include "framework_private.h" #include "bundle_private.h" #include "resolver.h" #include "utils.h" +#include "bundle_context_private.h" +#include "service_tracker_private.h" + celix_status_t bundle_createModule(bundle_pt bundle, module_pt *module); celix_status_t bundle_closeRevisions(const_bundle_pt bundle); @@ -637,3 +641,58 @@ const char* celix_bundle_getSymbolicName(const celix_bundle_t *bnd) { } return result; } + +celix_array_list_t* celix_bundle_listRegisteredServices(const celix_bundle_t *bnd) { + long bndId = celix_bundle_getId(bnd); + celix_array_list_t* result = celix_arrayList_create(); + celix_array_list_t *svcIds = celix_serviceRegistry_listServiceIdsForOwner(bnd->framework->registry, bndId); + for (int i = 0; i < celix_arrayList_size(svcIds); ++i) { + long svcId = celix_arrayList_getLong(svcIds, i); + celix_bundle_service_list_entry_t* entry = calloc(1, sizeof(*entry)); + entry->serviceId = svcId; + entry->bundleOwner = bndId; + celix_serviceRegistry_getServiceInfo(bnd->framework->registry, svcId, bndId, &entry->serviceName, &entry->serviceProperties, &entry->factory); + celix_arrayList_add(result, entry); + } + celix_arrayList_destroy(svcIds); + return result; +} + +void celix_bundle_destroyRegisteredServicesList(celix_array_list_t* list) { + if (list != NULL) { + for (int i = 0; i < celix_arrayList_size(list); ++i) { + celix_bundle_service_list_entry_t *entry = celix_arrayList_get(list, i); + free(entry->serviceName); + celix_properties_destroy(entry->serviceProperties); + free(entry); + } + } +} + +celix_array_list_t* celix_bundle_listServiceTrackers(const celix_bundle_t *bnd) { + celix_array_list_t* result = celix_arrayList_create(); + //FIXME: should not fall back to bundle context, but for now that is were the trackers are stored. + celixThreadMutex_lock(&bnd->context->mutex); + //hash_map_t *serviceTrackers; //key = trackerId, value = celix_service_tracker_t* + hash_map_iterator_t iter = hashMapIterator_construct(bnd->context->serviceTrackers); + while (hashMapIterator_hasNext(&iter)) { + celix_service_tracker_t *tracker = hashMapIterator_nextValue(&iter); + celix_bundle_service_tracker_list_entry_t *entry = calloc(1, sizeof(*entry)); + entry->filter = strndup(tracker->filter, 1024*1024*10); + entry->bundleOwner = celix_bundle_getId(bnd); + celix_arrayList_add(result, entry); + } + celixThreadMutex_unlock(&bnd->context->mutex); + return result; +} + + +void celix_bundle_destroyServiceTrackerList(celix_array_list_t* list) { + if (list != NULL) { + for (int i = 0; i < celix_arrayList_size(list); ++i) { + celix_bundle_service_tracker_list_entry_t *entry = celix_arrayList_get(list, i); + free(entry->filter); + free(entry); + } + } +} \ No newline at end of file diff --git a/libs/framework/src/bundle_context.c b/libs/framework/src/bundle_context.c index 430781c..00683c0 100644 --- a/libs/framework/src/bundle_context.c +++ b/libs/framework/src/bundle_context.c @@ -59,7 +59,7 @@ celix_status_t bundleContext_create(framework_pt framework, framework_logger_pt arrayList_create(&context->svcRegistrations); context->bundleTrackers = hashMap_create(NULL,NULL,NULL,NULL); context->serviceTrackers = hashMap_create(NULL,NULL,NULL,NULL); - context->serviceTrackerTrackers = hashMap_create(NULL,NULL,NULL,NULL); + context->metaTrackers = hashMap_create(NULL,NULL,NULL,NULL); context->nextTrackerId = 1L; *bundle_context = context; @@ -632,13 +632,13 @@ static void bundleContext_cleanupServiceTrackers(bundle_context_t *ctx) { } static void bundleContext_cleanupServiceTrackerTrackers(bundle_context_t *ctx) { - hash_map_iterator_t iter = hashMapIterator_construct(ctx->serviceTrackerTrackers); + hash_map_iterator_t iter = hashMapIterator_construct(ctx->metaTrackers); while (hashMapIterator_hasNext(&iter)) { celix_bundle_context_service_tracker_tracker_entry_t *entry = hashMapIterator_nextValue(&iter); serviceRegistration_unregister(entry->hookReg); free(entry); } - hashMap_destroy(ctx->serviceTrackerTrackers, false, false); + hashMap_destroy(ctx->metaTrackers, false, false); } @@ -656,9 +656,9 @@ void celix_bundleContext_stopTracker(bundle_context_t *ctx, long trackerId) { } else if (hashMap_containsKey(ctx->serviceTrackers, (void*)trackerId)) { found = true; serviceTracker = hashMap_remove(ctx->serviceTrackers, (void*)trackerId); - } else if (hashMap_containsKey(ctx->serviceTrackerTrackers, (void*)trackerId)) { + } else if (hashMap_containsKey(ctx->metaTrackers, (void*)trackerId)) { found = true; - svcTrackerTracker = hashMap_remove(ctx->serviceTrackerTrackers, (void*)trackerId); + svcTrackerTracker = hashMap_remove(ctx->metaTrackers, (void*)trackerId); } celixThreadMutex_unlock(&ctx->mutex); @@ -1016,7 +1016,7 @@ long celix_bundleContext_trackServiceTrackers( if (entry->hookReg != NULL) { celixThreadMutex_lock(&ctx->mutex); entry->trackerId = ctx->nextTrackerId++; - hashMap_put(ctx->serviceTrackerTrackers, (void*)entry->trackerId, entry); + hashMap_put(ctx->metaTrackers, (void*)entry->trackerId, entry); trackerId = entry->trackerId; celixThreadMutex_unlock(&ctx->mutex); } else { diff --git a/libs/framework/src/bundle_context_private.h b/libs/framework/src/bundle_context_private.h index d9e8d9d..e3b7619 100644 --- a/libs/framework/src/bundle_context_private.h +++ b/libs/framework/src/bundle_context_private.h @@ -49,13 +49,13 @@ struct celix_bundle_context { celix_framework_t *framework; celix_bundle_t *bundle; - celix_thread_mutex_t mutex; //protects fields below + celix_thread_mutex_t mutex; //protects fields below (NOTE/FIXME also used by bundle.c for listing service tracker usage) array_list_t *svcRegistrations; celix_dependency_manager_t *mng; long nextTrackerId; hash_map_t *bundleTrackers; //key = trackerId, value = celix_bundle_context_bundle_tracker_entry_t* hash_map_t *serviceTrackers; //key = trackerId, value = celix_service_tracker_t* - hash_map_t *serviceTrackerTrackers; //key = trackerId, value = celix_bundle_context_service_tracker_tracker_entry_t* + hash_map_t *metaTrackers; //key = trackerId, value = celix_bundle_context_service_tracker_tracker_entry_t* }; diff --git a/libs/framework/src/service_registration.c b/libs/framework/src/service_registration.c index 967f107..49f60c8 100644 --- a/libs/framework/src/service_registration.c +++ b/libs/framework/src/service_registration.c @@ -16,13 +16,6 @@ * specific language governing permissions and limitations * under the License. */ -/** - * service_registration.c - * - * \date Aug 6, 2010 - * \author <a href="mailto:[email protected]">Apache Celix Project Team</a> - * \copyright Apache License, Version 2.0 - */ #include <stdlib.h> #include <stdio.h> @@ -312,4 +305,14 @@ service_registration_t* celix_serviceRegistration_createServiceFactory( service_registration_pt registration = NULL; serviceRegistration_createInternal(callback, (celix_bundle_t*)bnd, serviceName, svcId, factory, props, CELIX_FACTORY_SERVICE, ®istration); return registration; +} + +bool serviceRegistration_isFactoryService(service_registration_t *registration) { + bool isFactory = false; + if (registration != NULL) { + celixThreadRwlock_readLock(®istration->lock); + isFactory = registration->svcType = CELIX_FACTORY_SERVICE || registration->svcType == CELIX_DEPRECATED_FACTORY_SERVICE; + celixThreadRwlock_unlock(®istration->lock); + } + return isFactory; } \ No newline at end of file diff --git a/libs/framework/src/service_registry.c b/libs/framework/src/service_registry.c index accd7b6..bf2a68b 100644 --- a/libs/framework/src/service_registry.c +++ b/libs/framework/src/service_registry.c @@ -916,4 +916,59 @@ static void celix_decreaseCountHook(celix_service_registry_listener_hook_entry_t celixThreadCondition_broadcast(&entry->cond); celixThreadMutex_unlock(&entry->mutex); } +} + +celix_array_list_t* celix_serviceRegistry_listServiceIdsForOwner(celix_service_registry_t* registry, long bndId) { + celix_array_list_t *result = celix_arrayList_create(); + celixThreadRwlock_readLock(®istry->lock); + celix_bundle_t *bundle = framework_getBundleById(registry->framework, bndId); + celix_array_list_t *registrations = bundle != NULL ? hashMap_get(registry->serviceRegistrations, bundle) : NULL; + if (registrations != NULL) { + for (int i = 0; i < celix_arrayList_size(registrations); ++i) { + service_registration_t *reg = celix_arrayList_get(registrations, i); + long svcId = serviceRegistration_getServiceId(reg); + celix_arrayList_addLong(result, svcId); + } + } + celixThreadRwlock_unlock(®istry->lock); + return result; +} + +bool celix_serviceRegistry_getServiceInfo( + celix_service_registry_t* registry, + long svcId, + long bndId, + char **outServiceName, + celix_properties_t **outServiceProperties, + bool *outIsFactory) { + bool found = false; + + celixThreadRwlock_readLock(®istry->lock); + celix_bundle_t *bundle = framework_getBundleById(registry->framework, bndId); + celix_array_list_t *registrations = bundle != NULL ? hashMap_get(registry->serviceRegistrations, bundle) : NULL; + if (registrations != NULL) { + for (int i = 0; i < celix_arrayList_size(registrations); ++i) { + service_registration_t *reg = celix_arrayList_get(registrations, i); + if (svcId == serviceRegistration_getServiceId(reg)) { + found = true; + if (outServiceName != NULL) { + const char *s = NULL; + serviceRegistration_getServiceName(reg, &s); + *outServiceName = strndup(s, 1024 * 1024 * 10); + } + if (outServiceProperties != NULL) { + celix_properties_t *p = NULL; + serviceRegistration_getProperties(reg, &p); + *outServiceProperties = celix_properties_copy(p); + } + if (outIsFactory != NULL) { + *outIsFactory = serviceRegistration_isFactoryService(reg); + } + break; + } + } + } + celixThreadRwlock_unlock(®istry->lock); + + return found; } \ No newline at end of file diff --git a/libs/framework/src/service_tracker.c b/libs/framework/src/service_tracker.c index 2dc0bba..9b24de8 100644 --- a/libs/framework/src/service_tracker.c +++ b/libs/framework/src/service_tracker.c @@ -52,14 +52,17 @@ static bool serviceTracker_useHighestRankingServiceInternal(celix_service_tracke static void serviceTracker_addInstanceFromShutdownList(celix_service_tracker_instance_t *instance); static void serviceTracker_remInstanceFromShutdownList(celix_service_tracker_instance_t *instance); -static celix_thread_once_t g_once = CELIX_THREAD_ONCE_INIT; -static celix_thread_mutex_t g_mutex; -static celix_thread_cond_t g_cond; +static celix_thread_once_t g_once = CELIX_THREAD_ONCE_INIT; //once for g_shutdownMutex, g_shutdownCond + + +static celix_thread_mutex_t g_shutdownMutex; +static celix_thread_cond_t g_shutdownCond; static celix_array_list_t *g_shutdownInstances = NULL; //value = celix_service_tracker_instance -> used for syncing with shutdown threads + static void serviceTracker_once(void) { - celixThreadMutex_create(&g_mutex, NULL); - celixThreadCondition_init(&g_cond, NULL); + celixThreadMutex_create(&g_shutdownMutex, NULL); + celixThreadCondition_init(&g_shutdownCond, NULL); } static inline celix_tracked_entry_t* tracked_create(service_reference_pt ref, void *svc, celix_properties_t *props, celix_bundle_t *bnd) { @@ -933,7 +936,7 @@ void celix_serviceTracker_useServices( void celix_serviceTracker_syncForFramework(void *fw) { celixThread_once(&g_once, serviceTracker_once); - celixThreadMutex_lock(&g_mutex); + celixThreadMutex_lock(&g_shutdownMutex); size_t count = 0; do { count = 0; @@ -946,7 +949,7 @@ void celix_serviceTracker_syncForFramework(void *fw) { } } if (count > 0) { - pthread_cond_wait(&g_cond, &g_mutex); + pthread_cond_wait(&g_shutdownCond, &g_shutdownMutex); } } while (count > 0); @@ -954,12 +957,12 @@ void celix_serviceTracker_syncForFramework(void *fw) { celix_arrayList_destroy(g_shutdownInstances); g_shutdownInstances = NULL; } - celixThreadMutex_unlock(&g_mutex); + celixThreadMutex_unlock(&g_shutdownMutex); } void celix_serviceTracker_syncForContext(void *ctx) { celixThread_once(&g_once, serviceTracker_once); - celixThreadMutex_lock(&g_mutex); + celixThreadMutex_lock(&g_shutdownMutex); size_t count; do { count = 0; @@ -972,7 +975,7 @@ void celix_serviceTracker_syncForContext(void *ctx) { } } if (count > 0) { - pthread_cond_wait(&g_cond, &g_mutex); + pthread_cond_wait(&g_shutdownCond, &g_shutdownMutex); } } while (count > 0); @@ -980,22 +983,22 @@ void celix_serviceTracker_syncForContext(void *ctx) { celix_arrayList_destroy(g_shutdownInstances); g_shutdownInstances = NULL; } - celixThreadMutex_unlock(&g_mutex); + celixThreadMutex_unlock(&g_shutdownMutex); } static void serviceTracker_addInstanceFromShutdownList(celix_service_tracker_instance_t *instance) { celixThread_once(&g_once, serviceTracker_once); - celixThreadMutex_lock(&g_mutex); + celixThreadMutex_lock(&g_shutdownMutex); if (g_shutdownInstances == NULL) { g_shutdownInstances = celix_arrayList_create(); } celix_arrayList_add(g_shutdownInstances, instance); - celixThreadMutex_unlock(&g_mutex); + celixThreadMutex_unlock(&g_shutdownMutex); } static void serviceTracker_remInstanceFromShutdownList(celix_service_tracker_instance_t *instance) { celixThread_once(&g_once, serviceTracker_once); - celixThreadMutex_lock(&g_mutex); + celixThreadMutex_lock(&g_shutdownMutex); if (g_shutdownInstances != NULL) { size_t size = celix_arrayList_size(g_shutdownInstances); for (size_t i = 0; i < size; ++i) { @@ -1008,7 +1011,7 @@ static void serviceTracker_remInstanceFromShutdownList(celix_service_tracker_ins celix_arrayList_destroy(g_shutdownInstances); g_shutdownInstances = NULL; } - celixThreadCondition_broadcast(&g_cond); + celixThreadCondition_broadcast(&g_shutdownCond); } - celixThreadMutex_unlock(&g_mutex); + celixThreadMutex_unlock(&g_shutdownMutex); }
