You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celix.apache.org by pn...@apache.org on 2020/02/02 21:17:25 UTC
[celix] 01/01: gh-144: Adds initial impl for the query command.
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 <pe...@gmail.com>
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:dev@celix.apache.org">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:dev@celix.apache.org">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:dev@celix.apache.org">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);
}