Repository: celix Updated Branches: refs/heads/develop a4a1f5000 -> 48aada3ab
CELIX-446: Adds an initial implementation of a service factory which does not use the service_registration pointer and adds some documentation for the service example Project: http://git-wip-us.apache.org/repos/asf/celix/repo Commit: http://git-wip-us.apache.org/repos/asf/celix/commit/626687fe Tree: http://git-wip-us.apache.org/repos/asf/celix/tree/626687fe Diff: http://git-wip-us.apache.org/repos/asf/celix/diff/626687fe Branch: refs/heads/develop Commit: 626687fea7a0095e384a1a692af6a3984b06ca94 Parents: a4a1f50 Author: Pepijn Noltes <[email protected]> Authored: Thu May 10 21:36:53 2018 +0200 Committer: Pepijn Noltes <[email protected]> Committed: Thu May 10 21:36:53 2018 +0200 ---------------------------------------------------------------------- .../services_example_c/CMakeLists.txt | 30 ++- .../celix-examples/services_example_c/README.md | 58 ++++++ .../services_example_c/api/example_calc.h | 1 + .../services_example_c/src/consumer_example.c | 184 ------------------ .../src/dynamic_consumer_example.c | 189 +++++++++++++++++++ .../src/dynamic_provider_example.c | 134 +++++++++++++ .../services_example_c/src/provider_example.c | 134 ------------- .../src/simple_consumer_example.c | 85 +++++++++ .../src/simple_provider_example.c | 73 +++++++ framework/include/bundle_context.h | 61 +++++- framework/include/celix_service_factory.h | 43 +++++ framework/include/celix_types.h | 2 + framework/include/service_factory.h | 22 +-- framework/include/service_registry.h | 14 +- framework/private/mock/bundle_context_mock.c | 21 +++ framework/private/mock/framework_mock.c | 10 +- .../private/mock/service_registration_mock.c | 17 ++ framework/private/mock/service_registry_mock.c | 18 ++ .../private/test/service_registration_test.cpp | 9 +- framework/src/bundle_context.c | 39 +++- framework/src/framework.c | 18 ++ framework/src/framework_private.h | 3 +- framework/src/service_registration.c | 61 +++--- framework/src/service_registration_private.h | 22 ++- framework/src/service_registry.c | 25 ++- framework/src/service_registry_private.h | 2 +- framework/tst/bundle_context_services_test.cpp | 46 +++++ 27 files changed, 922 insertions(+), 399 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/celix/blob/626687fe/examples/celix-examples/services_example_c/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/examples/celix-examples/services_example_c/CMakeLists.txt b/examples/celix-examples/services_example_c/CMakeLists.txt index f56ddd8..43b88b2 100644 --- a/examples/celix-examples/services_example_c/CMakeLists.txt +++ b/examples/celix-examples/services_example_c/CMakeLists.txt @@ -21,24 +21,48 @@ target_include_directories(services_example_c_api INTERFACE api) add_celix_bundle(provider_example VERSION 1.0.0 - SOURCES src/provider_example.c + SOURCES src/simple_provider_example.c ) target_link_libraries(provider_example PRIVATE services_example_c_api) add_celix_bundle(consumer_example VERSION 1.0.0 - SOURCES src/consumer_example.c + SOURCES src/simple_consumer_example.c ) target_link_libraries(consumer_example PRIVATE services_example_c_api) + + +add_celix_bundle(dynamic_provider_example + VERSION 1.0.0 + SOURCES src/dynamic_provider_example.c +) +target_link_libraries(dynamic_provider_example PRIVATE services_example_c_api) + +add_celix_bundle(dynamic_consumer_example + VERSION 1.0.0 + SOURCES src/dynamic_consumer_example.c +) +target_link_libraries(dynamic_consumer_example PRIVATE services_example_c_api) + if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") - target_compile_definitions(consumer_example PRIVATE USE_NESTED_FUNCTION_EXAMPLE) + target_compile_definitions(dynamic_consumer_example PRIVATE USE_NESTED_FUNCTION_EXAMPLE) endif() add_celix_container(services_example_c + GROUP services_example BUNDLES Celix::shell Celix::shell_tui provider_example consumer_example ) + +add_celix_container(dynamic_services_example_c + GROUP services_example + BUNDLES + Celix::shell + Celix::shell_tui + dynamic_provider_example + dynamic_consumer_example +) http://git-wip-us.apache.org/repos/asf/celix/blob/626687fe/examples/celix-examples/services_example_c/README.md ---------------------------------------------------------------------- diff --git a/examples/celix-examples/services_example_c/README.md b/examples/celix-examples/services_example_c/README.md new file mode 100644 index 0000000..a4f50ba --- /dev/null +++ b/examples/celix-examples/services_example_c/README.md @@ -0,0 +1,58 @@ +<!-- +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +--> + +# Intro + +This example show how services can be provided and consumer by bundles. + +The example uses the `celix_bundleContext_registerService` to provide +services and uses a combination of `celix_bundleContext_useService`, + `celix_bundleContext_useServices` and `celix_bundleContext_trackServices` + to consume services. + + TODO intro bundle context + + See the `bundle_context.h` for documentation about these - and other -functions + +# Simple Service Provider & Consumer Example + +The simple provider/consumer example can be executed by launching the +`services_example_c` executable target +(build in `${CMAKE_BUILD_DIR}/deploy/services_example/services_example_c`) + +In this example the provide bundle only register one calc service. And +the consumer bundle tries to use this during startup and registerd +a service tracker for the calc service. + +Try stopping/starting the provider / consumer bundles (respectively bundle id 3 & 4) +to see how this work runtime. E.g. use `stop 3`, `stop 4`, `start 3`, `start 4` in different combinations. + + +# Dynamic Service Provider & Consumer Example + +The dynamic provider/consumer example can be executed by launching the +`dynamic_services_example_c` executable target +(build in `${CMAKE_BUILD_DIR}/deploy/services_example/dynamic_services_example_c`) + +The dynamic service provide / consumer example show how the framework copes +with the dynamic behaviour of services. + +This this example the provided dynammically register more and less calc services in a thread. +The consumer bundle uses these services in a every 5 seconds and print some info. + +Hopefully this example will give an idea how services can be safely used and tracked in a dynamic environment. + http://git-wip-us.apache.org/repos/asf/celix/blob/626687fe/examples/celix-examples/services_example_c/api/example_calc.h ---------------------------------------------------------------------- diff --git a/examples/celix-examples/services_example_c/api/example_calc.h b/examples/celix-examples/services_example_c/api/example_calc.h index 89481fa..8afe6c3 100644 --- a/examples/celix-examples/services_example_c/api/example_calc.h +++ b/examples/celix-examples/services_example_c/api/example_calc.h @@ -21,6 +21,7 @@ #define CELIX_EXAMPLE_CALC_H #define EXAMPLE_CALC_NAME "example_calc" +#define EXAMPLE_CALC_VERSION "1.0.0" struct example_calc { void *handle; http://git-wip-us.apache.org/repos/asf/celix/blob/626687fe/examples/celix-examples/services_example_c/src/consumer_example.c ---------------------------------------------------------------------- diff --git a/examples/celix-examples/services_example_c/src/consumer_example.c b/examples/celix-examples/services_example_c/src/consumer_example.c deleted file mode 100644 index 899cb57..0000000 --- a/examples/celix-examples/services_example_c/src/consumer_example.c +++ /dev/null @@ -1,184 +0,0 @@ -/** - *Licensed to the Apache Software Foundation (ASF) under one - *or more contributor license agreements. See the NOTICE file - *distributed with this work for additional information - *regarding copyright ownership. The ASF licenses this file - *to you under the Apache License, Version 2.0 (the - *"License"); you may not use this file except in compliance - *with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - *Unless required by applicable law or agreed to in writing, - *software distributed under the License is distributed on an - *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - *specific language governing permissions and limitations - *under the License. - */ - -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <constants.h> - -#include "example_calc.h" -#include "bundle_activator.h" - -typedef struct activator_data { - celix_bundle_context_t *ctx; - pthread_t thread; - - pthread_mutex_t mutex; //protects running - bool running; - int trackCount; -} activator_data_t; - -static bool isRunning(activator_data_t *data) { - bool result = false; - pthread_mutex_lock(&data->mutex); - result = data->running; - pthread_mutex_unlock(&data->mutex); - return result; -} - -static void setRunning(activator_data_t *data, bool val) { - pthread_mutex_lock(&data->mutex); - data->running = val; - pthread_mutex_unlock(&data->mutex); -} - -struct info { - int result; - int count; -}; - -static void useCalc(void *handle, void *svc) { - struct info *i = handle; - example_calc_t *calc = svc; - i->result += calc->calc(calc->handle, 1); - i->count += 1; -} - -static void gccExample(activator_data_t *data) { -#ifdef USE_NESTED_FUNCTION_EXAMPLE - - int result = 0; - long rank = 0; - long svcId = 0; - - void use(void *handle, void *svc, const celix_properties_t *props) { - example_calc_t *calc = svc; - rank = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_RANKING, -1L); - svcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, -1L); - result = calc->calc(calc->handle, 1); - } - - celix_service_use_options_t opts; - memset(&opts, 0, sizeof(opts)); - - opts.serviceName = EXAMPLE_CALC_NAME; - opts.callbackHandle = NULL; //can be null for trampolines - opts.useWithProperties = use; - bool called = celix_bundleContext_useServiceWithOptions(data->ctx, &opts); - - printf("Called func %s. Result is %i, rank is %li and svc id is %li\n", called ? "called" : "not called", result, rank, svcId); - -#endif -} - -static void addSvc(activator_data_t *data, void *svc __attribute__((unused))) { - pthread_mutex_lock(&data->mutex); - data->trackCount += 1; - pthread_mutex_unlock(&data->mutex); -} - -static void removeSvc(activator_data_t *data, void *svc __attribute__((unused))) { - pthread_mutex_lock(&data->mutex); - data->trackCount -= 1; - pthread_mutex_unlock(&data->mutex); -} - -static void useHighest(activator_data_t *data __attribute__((unused)), example_calc_t *svc, const celix_properties_t *props) { - int result = svc->calc(svc->handle, 2); - long svcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, -1L); - long rank = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_RANKING, -1L); - printf("Called highest ranking service. Result is %i, svc id is %li, svc ranking is %li\n", result, svcId, rank); -} - - -void * run(void *handle) { - activator_data_t *data = handle; - - printf("starting consumer thread\n"); - long trkId = celix_bundleContext_trackServices(data->ctx, EXAMPLE_CALC_NAME, data, (void*)addSvc, (void*)removeSvc); - - while (isRunning(data)) { - struct info info; - info.result = 0; - info.count = 0; - celix_bundleContext_useServices(data->ctx, EXAMPLE_CALC_NAME, &info, useCalc); - printf("Called calc services %i times, total result is %i\n", info.count, info.result); - - gccExample(data); //gcc trampolines example (nested functions) - - celix_service_use_options_t opts; - memset(&opts, 0, sizeof(opts)); - - opts.serviceName = EXAMPLE_CALC_NAME; - opts.callbackHandle = data; - opts.useWithProperties = (void*)useHighest; - celix_bundleContext_useServiceWithOptions(data->ctx, &opts); - - pthread_mutex_lock(&data->mutex); - int count = data->trackCount; - pthread_mutex_unlock(&data->mutex); - printf("Current tracking count is %i\n", count); - - sleep(5); - } - - celix_bundleContext_stopTracker(data->ctx, trkId); - printf("exiting consumer thread\n"); - - pthread_exit(NULL); - return NULL; -} - -celix_status_t bundleActivator_create(celix_bundle_context_t *ctx, void **out) { - celix_status_t status = CELIX_SUCCESS; - activator_data_t *data = calloc(1, sizeof(*data)); - if (data != NULL) { - data->ctx = ctx; - data->trackCount = 0; - data->running = true; - pthread_mutex_init(&data->mutex, NULL); - *out = data; - } else { - status = CELIX_ENOMEM; - } - return status; -} - -celix_status_t bundleActivator_start(void * handle, celix_bundle_context_t *ctx) { - activator_data_t *data = handle; - pthread_create(&data->thread, NULL, run, data); - return CELIX_SUCCESS; -} - -celix_status_t bundleActivator_stop(void * handle, celix_bundle_context_t *ctx) { - activator_data_t *data = handle; - setRunning(data, false); - pthread_join(data->thread, NULL); - return CELIX_SUCCESS; -} - -celix_status_t bundleActivator_destroy(void * handle, celix_bundle_context_t *ctx) { - activator_data_t *data = handle; - if (data != NULL) { - pthread_mutex_destroy(&data->mutex); - free(data); - } - return CELIX_SUCCESS; -} http://git-wip-us.apache.org/repos/asf/celix/blob/626687fe/examples/celix-examples/services_example_c/src/dynamic_consumer_example.c ---------------------------------------------------------------------- diff --git a/examples/celix-examples/services_example_c/src/dynamic_consumer_example.c b/examples/celix-examples/services_example_c/src/dynamic_consumer_example.c new file mode 100644 index 0000000..5a676d6 --- /dev/null +++ b/examples/celix-examples/services_example_c/src/dynamic_consumer_example.c @@ -0,0 +1,189 @@ +/** + *Licensed to the Apache Software Foundation (ASF) under one + *or more contributor license agreements. See the NOTICE file + *distributed with this work for additional information + *regarding copyright ownership. The ASF licenses this file + *to you under the Apache License, Version 2.0 (the + *"License"); you may not use this file except in compliance + *with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + *Unless required by applicable law or agreed to in writing, + *software distributed under the License is distributed on an + *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + *specific language governing permissions and limitations + *under the License. + */ + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <constants.h> + +#include "example_calc.h" +#include "bundle_activator.h" + +typedef struct activator_data { + celix_bundle_context_t *ctx; + pthread_t thread; + + pthread_mutex_t mutex; //protects running + bool running; + int trackCount; +} activator_data_t; + +static bool isRunning(activator_data_t *data) { + bool result = false; + pthread_mutex_lock(&data->mutex); + result = data->running; + pthread_mutex_unlock(&data->mutex); + return result; +} + +static void setRunning(activator_data_t *data, bool val) { + pthread_mutex_lock(&data->mutex); + data->running = val; + pthread_mutex_unlock(&data->mutex); +} + +struct info { + int result; + int count; +}; + +static void useCalc(void *handle, void *svc) { + struct info *i = handle; + example_calc_t *calc = svc; + i->result += calc->calc(calc->handle, 1); + i->count += 1; +} + +static void gccExample(activator_data_t *data) { +#ifdef USE_NESTED_FUNCTION_EXAMPLE + + int result = 0; + long rank = 0; + long svcId = 0; + + void use(void *handle, void *svc, const celix_properties_t *props) { + example_calc_t *calc = svc; + rank = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_RANKING, -1L); + svcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, -1L); + result = calc->calc(calc->handle, 1); + } + + celix_service_use_options_t opts; + memset(&opts, 0, sizeof(opts)); + + opts.serviceName = EXAMPLE_CALC_NAME; + opts.callbackHandle = NULL; //can be null for trampolines + opts.useWithProperties = use; + bool called = celix_bundleContext_useServiceWithOptions(data->ctx, &opts); + + printf("Called func %s. Result is %i, rank is %li and svc id is %li\n", called ? "called" : "not called", result, rank, svcId); + +#endif +} + +static void addSvc(activator_data_t *data, void *svc __attribute__((unused))) { + pthread_mutex_lock(&data->mutex); + data->trackCount += 1; + pthread_mutex_unlock(&data->mutex); +} + +static void removeSvc(activator_data_t *data, void *svc __attribute__((unused))) { + pthread_mutex_lock(&data->mutex); + data->trackCount -= 1; + pthread_mutex_unlock(&data->mutex); +} + +static void useHighest(activator_data_t *data __attribute__((unused)), example_calc_t *svc, const celix_properties_t *props) { + int result = svc->calc(svc->handle, 2); + long svcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, -1L); + long rank = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_RANKING, -1L); + printf("Called highest ranking service. Result is %i, svc id is %li, svc ranking is %li\n", result, svcId, rank); +} + + +void * run(void *handle) { + activator_data_t *data = handle; + + printf("starting consumer thread\n"); + celix_service_tracking_options_t opts; + opts.serviceName = EXAMPLE_CALC_NAME; + opts.callbackHandle = data; + opts.addWithProperties = (void*)addSvc; + opts.removeWithProperties = (void*)removeSvc; + long trkId = celix_bundleContext_trackServicesWithOptions(data->ctx, &opts); + + while (isRunning(data)) { + struct info info; + info.result = 0; + info.count = 0; + celix_bundleContext_useServices(data->ctx, EXAMPLE_CALC_NAME, &info, useCalc); + printf("Called calc services %i times, total result is %i\n", info.count, info.result); + + gccExample(data); //gcc trampolines example (nested functions) + + celix_service_use_options_t opts; + memset(&opts, 0, sizeof(opts)); + + opts.serviceName = EXAMPLE_CALC_NAME; + opts.callbackHandle = data; + opts.useWithProperties = (void*)useHighest; + celix_bundleContext_useServiceWithOptions(data->ctx, &opts); + + pthread_mutex_lock(&data->mutex); + int count = data->trackCount; + pthread_mutex_unlock(&data->mutex); + printf("Current tracking count is %i\n", count); + + sleep(5); + } + + celix_bundleContext_stopTracker(data->ctx, trkId); + printf("exiting consumer thread\n"); + + pthread_exit(NULL); + return NULL; +} + +celix_status_t bundleActivator_create(celix_bundle_context_t *ctx, void **out) { + celix_status_t status = CELIX_SUCCESS; + activator_data_t *data = calloc(1, sizeof(*data)); + if (data != NULL) { + data->ctx = ctx; + data->trackCount = 0; + data->running = true; + pthread_mutex_init(&data->mutex, NULL); + *out = data; + } else { + status = CELIX_ENOMEM; + } + return status; +} + +celix_status_t bundleActivator_start(void * handle, celix_bundle_context_t *ctx) { + activator_data_t *data = handle; + pthread_create(&data->thread, NULL, run, data); + return CELIX_SUCCESS; +} + +celix_status_t bundleActivator_stop(void * handle, celix_bundle_context_t *ctx) { + activator_data_t *data = handle; + setRunning(data, false); + pthread_join(data->thread, NULL); + return CELIX_SUCCESS; +} + +celix_status_t bundleActivator_destroy(void * handle, celix_bundle_context_t *ctx) { + activator_data_t *data = handle; + if (data != NULL) { + pthread_mutex_destroy(&data->mutex); + free(data); + } + return CELIX_SUCCESS; +} http://git-wip-us.apache.org/repos/asf/celix/blob/626687fe/examples/celix-examples/services_example_c/src/dynamic_provider_example.c ---------------------------------------------------------------------- diff --git a/examples/celix-examples/services_example_c/src/dynamic_provider_example.c b/examples/celix-examples/services_example_c/src/dynamic_provider_example.c new file mode 100644 index 0000000..f322303 --- /dev/null +++ b/examples/celix-examples/services_example_c/src/dynamic_provider_example.c @@ -0,0 +1,134 @@ +/** + *Licensed to the Apache Software Foundation (ASF) under one + *or more contributor license agreements. See the NOTICE file + *distributed with this work for additional information + *regarding copyright ownership. The ASF licenses this file + *to you under the Apache License, Version 2.0 (the + *"License"); you may not use this file except in compliance + *with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + *Unless required by applicable law or agreed to in writing, + *software distributed under the License is distributed on an + *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + *specific language governing permissions and limitations + *under the License. + */ + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> + +#include "example_calc.h" +#include "bundle_activator.h" +#include "constants.h" + +typedef struct activator_data { + long svcIds[100]; + example_calc_t svc; + celix_bundle_context_t *ctx; + pthread_t thread; + + pthread_mutex_t mutex; //protects running + bool running; +} activator_data_t; + + +static int calc(void *handle __attribute__((unused)), int input) { + return 42 * input; +} + +static bool isRunning(activator_data_t *data) { + bool result = false; + pthread_mutex_lock(&data->mutex); + result = data->running; + pthread_mutex_unlock(&data->mutex); + return result; +} + +static void setRunning(activator_data_t *data, bool val) { + pthread_mutex_lock(&data->mutex); + data->running = val; + pthread_mutex_unlock(&data->mutex); +} + +void * run(void *handle) { + activator_data_t *data = handle; + + printf("starting service register thread\n"); + + int i = 0; + bool up = true; + while (isRunning(data)) { + if (up) { + properties_t *props = properties_create(); + celix_properties_setLong(props, OSGI_FRAMEWORK_SERVICE_RANKING, rand()); + data->svcIds[i++] = celix_bundleContext_registerService(data->ctx, EXAMPLE_CALC_NAME, &data->svc, NULL, props); + } else { //down + celix_bundleContext_unregisterService(data->ctx, data->svcIds[i--]); + } + if (i == 99) { + up = false; + } else if (i == 0) { + up = true; + } + usleep(100000); + } + + for (int i = 0; i < 100; ++i) { + long id = data->svcIds[i]; + if (id >=0 ) { + celix_bundleContext_unregisterService(data->ctx, id); + } + } + + printf("exiting service register thread\n"); + + pthread_exit(NULL); + return NULL; +} + +celix_status_t bundleActivator_create(celix_bundle_context_t *ctx, void **out) { + celix_status_t status = CELIX_SUCCESS; + activator_data_t *data = calloc(1, sizeof(*data)); + if (data != NULL) { + data->svc.handle = data; + data->svc.calc = calc; + data->ctx = ctx; + data->running = true; + pthread_mutex_init(&data->mutex, NULL); + + for (int i = 0; i < 100; ++i) { + data->svcIds[i] = -1L; + } + + *out = data; + } else { + status = CELIX_ENOMEM; + } + return status; +} + +celix_status_t bundleActivator_start(void * handle, celix_bundle_context_t *ctx) { + activator_data_t *data = handle; + pthread_create(&data->thread, NULL, run ,data); + return CELIX_SUCCESS; +} + +celix_status_t bundleActivator_stop(void * handle, celix_bundle_context_t *ctx) { + activator_data_t *data = handle; + setRunning(data, false); + pthread_join(data->thread, NULL); + return CELIX_SUCCESS; +} + +celix_status_t bundleActivator_destroy(void * handle, celix_bundle_context_t *ctx) { + activator_data_t *data = handle; + if (data != NULL) { + pthread_mutex_destroy(&data->mutex); + free(data); + } + return CELIX_SUCCESS; +} http://git-wip-us.apache.org/repos/asf/celix/blob/626687fe/examples/celix-examples/services_example_c/src/provider_example.c ---------------------------------------------------------------------- diff --git a/examples/celix-examples/services_example_c/src/provider_example.c b/examples/celix-examples/services_example_c/src/provider_example.c deleted file mode 100644 index f322303..0000000 --- a/examples/celix-examples/services_example_c/src/provider_example.c +++ /dev/null @@ -1,134 +0,0 @@ -/** - *Licensed to the Apache Software Foundation (ASF) under one - *or more contributor license agreements. See the NOTICE file - *distributed with this work for additional information - *regarding copyright ownership. The ASF licenses this file - *to you under the Apache License, Version 2.0 (the - *"License"); you may not use this file except in compliance - *with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - *Unless required by applicable law or agreed to in writing, - *software distributed under the License is distributed on an - *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - *specific language governing permissions and limitations - *under the License. - */ - -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> - -#include "example_calc.h" -#include "bundle_activator.h" -#include "constants.h" - -typedef struct activator_data { - long svcIds[100]; - example_calc_t svc; - celix_bundle_context_t *ctx; - pthread_t thread; - - pthread_mutex_t mutex; //protects running - bool running; -} activator_data_t; - - -static int calc(void *handle __attribute__((unused)), int input) { - return 42 * input; -} - -static bool isRunning(activator_data_t *data) { - bool result = false; - pthread_mutex_lock(&data->mutex); - result = data->running; - pthread_mutex_unlock(&data->mutex); - return result; -} - -static void setRunning(activator_data_t *data, bool val) { - pthread_mutex_lock(&data->mutex); - data->running = val; - pthread_mutex_unlock(&data->mutex); -} - -void * run(void *handle) { - activator_data_t *data = handle; - - printf("starting service register thread\n"); - - int i = 0; - bool up = true; - while (isRunning(data)) { - if (up) { - properties_t *props = properties_create(); - celix_properties_setLong(props, OSGI_FRAMEWORK_SERVICE_RANKING, rand()); - data->svcIds[i++] = celix_bundleContext_registerService(data->ctx, EXAMPLE_CALC_NAME, &data->svc, NULL, props); - } else { //down - celix_bundleContext_unregisterService(data->ctx, data->svcIds[i--]); - } - if (i == 99) { - up = false; - } else if (i == 0) { - up = true; - } - usleep(100000); - } - - for (int i = 0; i < 100; ++i) { - long id = data->svcIds[i]; - if (id >=0 ) { - celix_bundleContext_unregisterService(data->ctx, id); - } - } - - printf("exiting service register thread\n"); - - pthread_exit(NULL); - return NULL; -} - -celix_status_t bundleActivator_create(celix_bundle_context_t *ctx, void **out) { - celix_status_t status = CELIX_SUCCESS; - activator_data_t *data = calloc(1, sizeof(*data)); - if (data != NULL) { - data->svc.handle = data; - data->svc.calc = calc; - data->ctx = ctx; - data->running = true; - pthread_mutex_init(&data->mutex, NULL); - - for (int i = 0; i < 100; ++i) { - data->svcIds[i] = -1L; - } - - *out = data; - } else { - status = CELIX_ENOMEM; - } - return status; -} - -celix_status_t bundleActivator_start(void * handle, celix_bundle_context_t *ctx) { - activator_data_t *data = handle; - pthread_create(&data->thread, NULL, run ,data); - return CELIX_SUCCESS; -} - -celix_status_t bundleActivator_stop(void * handle, celix_bundle_context_t *ctx) { - activator_data_t *data = handle; - setRunning(data, false); - pthread_join(data->thread, NULL); - return CELIX_SUCCESS; -} - -celix_status_t bundleActivator_destroy(void * handle, celix_bundle_context_t *ctx) { - activator_data_t *data = handle; - if (data != NULL) { - pthread_mutex_destroy(&data->mutex); - free(data); - } - return CELIX_SUCCESS; -} http://git-wip-us.apache.org/repos/asf/celix/blob/626687fe/examples/celix-examples/services_example_c/src/simple_consumer_example.c ---------------------------------------------------------------------- diff --git a/examples/celix-examples/services_example_c/src/simple_consumer_example.c b/examples/celix-examples/services_example_c/src/simple_consumer_example.c new file mode 100644 index 0000000..edf88c6 --- /dev/null +++ b/examples/celix-examples/services_example_c/src/simple_consumer_example.c @@ -0,0 +1,85 @@ +/** + *Licensed to the Apache Software Foundation (ASF) under one + *or more contributor license agreements. See the NOTICE file + *distributed with this work for additional information + *regarding copyright ownership. The ASF licenses this file + *to you under the Apache License, Version 2.0 (the + *"License"); you may not use this file except in compliance + *with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + *Unless required by applicable law or agreed to in writing, + *software distributed under the License is distributed on an + *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + *specific language governing permissions and limitations + *under the License. + */ + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <constants.h> + +#include "example_calc.h" +#include "bundle_activator.h" + +typedef struct activator_data { + celix_bundle_context_t *ctx; + long trkId; +} activator_data_t; + + +static void addSvc(activator_data_t *data __attribute__((unused)), example_calc_t *calc) { + int result = calc->calc(calc->handle, 2); + printf("Added calc service, result is %i\n", result); +} + +static void removeSvc(activator_data_t *data __attribute__((unused)), example_calc_t *calc) { + int result = calc->calc(calc->handle, 3); + printf("Removing calc service, result is %i\n", result); +} + +static void useCalc(activator_data_t *data __attribute__((unused)), example_calc_t *calc) { + int result = calc->calc(calc->handle, 2); + printf("Called highest ranking service. Result is %i\n", result); +} + +celix_status_t bundleActivator_create(celix_bundle_context_t *ctx, void **out) { + celix_status_t status = CELIX_SUCCESS; + activator_data_t *data = calloc(1, sizeof(*data)); + if (data != NULL) { + data->ctx = ctx; + data->trkId = -1L; + *out = data; + } else { + status = CELIX_ENOMEM; + } + return status; +} + +celix_status_t bundleActivator_start(void * handle, celix_bundle_context_t *ctx) { + activator_data_t *data = handle; + + printf("Starting service tracker\n"); + data->trkId = celix_bundleContext_trackServices(data->ctx, EXAMPLE_CALC_NAME, data, (void*)addSvc, (void*)removeSvc); + + printf("Trying to use calc service\n"); + celix_bundleContext_useService(data->ctx, EXAMPLE_CALC_NAME, data, (void*)useCalc); + + return CELIX_SUCCESS; +} + +celix_status_t bundleActivator_stop(void * handle, celix_bundle_context_t *ctx) { + activator_data_t *data = handle; + celix_bundleContext_stopTracker(data->ctx, data->trkId); + return CELIX_SUCCESS; +} + +celix_status_t bundleActivator_destroy(void * handle, celix_bundle_context_t *ctx) { + activator_data_t *data = handle; + free(data); + return CELIX_SUCCESS; +} http://git-wip-us.apache.org/repos/asf/celix/blob/626687fe/examples/celix-examples/services_example_c/src/simple_provider_example.c ---------------------------------------------------------------------- diff --git a/examples/celix-examples/services_example_c/src/simple_provider_example.c b/examples/celix-examples/services_example_c/src/simple_provider_example.c new file mode 100644 index 0000000..765a49e --- /dev/null +++ b/examples/celix-examples/services_example_c/src/simple_provider_example.c @@ -0,0 +1,73 @@ +/** + *Licensed to the Apache Software Foundation (ASF) under one + *or more contributor license agreements. See the NOTICE file + *distributed with this work for additional information + *regarding copyright ownership. The ASF licenses this file + *to you under the Apache License, Version 2.0 (the + *"License"); you may not use this file except in compliance + *with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + *Unless required by applicable law or agreed to in writing, + *software distributed under the License is distributed on an + *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + *specific language governing permissions and limitations + *under the License. + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "example_calc.h" +#include "bundle_activator.h" +#include "constants.h" + +typedef struct activator_data { + celix_bundle_context_t *ctx; + example_calc_t svc; + int seed; + long svcId; +} activator_data_t; + + +static int calc(activator_data_t *data, int input) { + return data->seed * input; +} + +celix_status_t bundleActivator_create(celix_bundle_context_t *ctx, void **out) { + celix_status_t status = CELIX_SUCCESS; + activator_data_t *data = calloc(1, sizeof(*data)); + if (data != NULL) { + data->svc.handle = data; + data->svc.calc = (void*)calc; + data->ctx = ctx; + data->seed = 42; + data->svcId = -1L; + *out = data; + } else { + status = CELIX_ENOMEM; + } + return status; +} + +celix_status_t bundleActivator_start(void * handle, celix_bundle_context_t *ctx) { + activator_data_t *data = handle; + data->svcId = celix_bundleContext_registerService(data->ctx, EXAMPLE_CALC_NAME, &data->svc, EXAMPLE_CALC_VERSION, NULL); + printf("Registered calc service with service id %li\n", data->svcId); + return CELIX_SUCCESS; +} + +celix_status_t bundleActivator_stop(void * handle, celix_bundle_context_t *ctx) { + activator_data_t *data = handle; + celix_bundleContext_unregisterService(data->ctx, data->svcId); + printf("Unregistered calc service with service id %li\n", data->svcId); + return CELIX_SUCCESS; +} + +celix_status_t bundleActivator_destroy(void * handle, celix_bundle_context_t *ctx) { + activator_data_t *data = handle; + free(data); + return CELIX_SUCCESS; +} http://git-wip-us.apache.org/repos/asf/celix/blob/626687fe/framework/include/bundle_context.h ---------------------------------------------------------------------- diff --git a/framework/include/bundle_context.h b/framework/include/bundle_context.h index ec974fa..44cca39 100644 --- a/framework/include/bundle_context.h +++ b/framework/include/bundle_context.h @@ -29,6 +29,7 @@ #include "celix_types.h" #include "service_factory.h" +#include "celix_service_factory.h" #include "service_listener.h" #include "bundle_listener.h" #include "framework_listener.h" @@ -201,7 +202,8 @@ dm_dependency_manager_t* celix_bundleContext_getDependencyManager(celix_bundle_c * @param ctx The bundle context * @param serviceName the service name, cannot be NULL * @param svc the service object. Normally a pointer to a service struct (e.g. a struct with function pointers) - * @param properties The meta properties assiated with the service. The service registration will take ownership of the properties (e.g. no destroy needed) + * @param serviceVersion The optional service version. + * @param properties The meta properties associated with the service. The service registration will take ownership of the properties (e.g. no destroy needed) * @return The serviceId, which should be >= 0. If < 0 then the registration was unsuccessful. */ long celix_bundleContext_registerService(celix_bundle_context_t *ctx, const char *serviceName, void *svc, const char *serviceVersion, celix_properties_t *properties); @@ -211,17 +213,56 @@ long celix_bundleContext_registerService(celix_bundle_context_t *ctx, const char * * @param ctx The bundle context * @param serviceName the service name, cannot be NULL -* @param svc the service object. Normally a pointer to a service struct (e.g. a struct with function pointers) -* @param properties The meta properties assiated with the service. The service registration will take ownership of the properties +* @param svc Pointer to the service. Normally a pointer to a service struct (e.g. a struct with function pointers) +* @param serviceVersion The optional service version. +* @param lang The service language. Will be set to CELIX_FRAMEWORK_SERVICE_LANGUAGE_C if NULL is provided. +* @param properties The meta properties associated with the service. The service registration will take ownership of the properties * @return The serviceId, which should >= 0. If < 0 then the registration was unsuccessful. */ long celix_bundleContext_registerServiceForLang(celix_bundle_context_t *ctx, const char *serviceName, void *svc, const char *serviceVersion, const char* lang, celix_properties_t *properties); -//TODO register service factory +/** + * Register a service factory in the framework (for the C language). + * THe service factory will be called for every bundle requesting/de-requesting a service. This gives the provider the + * option to create bundle specific service instances. + * + * When a service is requested for a bundle the getService of the factory service will be called. This function must + * return a valid pointer to a service conform the registered service name or NULL. + * When a service in no longer needed for a bundle (e.g. ending the useService(s) calls when a service tacker is stopped) + * the ungetService function of the service factory will be called. + * + * @param ctx The bundle context + * @param serviceName The required service name of the services this factory will produce. + * @param factory The pointer to the factory service. + * @param serviceVersion The optional service version. + * @param properties The optional service factory properties. For a service consumer this will be seen as the service properties. + * @return The service id of the service factory or < 0 if the registration was unsuccessful. + */ +long celix_bundleContext_registerServiceFactory(celix_bundle_context_t *ctx, const char *serviceName, celix_service_factory_t *factory, const char *serviceVersion, celix_properties_t *properties); + +/** + * Register a service factory in the framework. + * THe service factory will be called for every bundle requesting/de-requesting a service. This gives the provider the + * option to create bundle specific service instances. + * + * When a service is requested for a bundle the getService of the factory service will be called. This function must + * return a valid pointer to a service conform the registered service name or NULL. + * When a service in no longer needed for a bundle (e.g. ending the useService(s) calls when a service tacker is stopped) + * the ungetService function of the service factory will be called. + * + * @param ctx The bundle context + * @param serviceName The required service name of the services this factory will produce. + * @param factory The pointer to the factory service. + * @param serviceVersion The optional service version. + * @param lang The d service language. Will be set to CELIX_FRAMEWORK_SERVICE_LANGUAGE_C if NULL is provided. + * @param properties The optional service factory properties. For a service consumer this will be seen as the service properties. + * @return The service id of the service factory or < 0 if the registration was unsuccessful. + */ +long celix_bundleContext_registerServiceFactorForLang(celix_bundle_context_t *ctx, const char *serviceName, celix_service_factory_t *factory, const char *serviceVersion, const char *lang, celix_properties_t *properties); /** - * Unregister the service with service id. The service will only be unregistered if the bundle of the bundle context - * is the owner of the service. + * Unregister the service or service factory with service id. + * The service will only be unregistered if the bundle of the bundle context is the owner of the service. * * Will log an error if service id is unknown. Will silently ignore services ids < 0. * @@ -557,10 +598,12 @@ void celix_bundleContext_useBundle( void (*use)(void *handle, const celix_bundle_t *bundle) ); -//TODO add useBundleWithState (bit wise or?) +//TODO add useBundleWithOptions (e.g. which state) + + +//TODO findBundles -//TODO except framework & own bundle /** * Use the currently active (started) bundles. * The provided callback will be called for all the currently started bundles. @@ -577,7 +620,7 @@ void celix_bundleContext_useBundles( ); -//TODO trackerServiceTracker +//TODO trackServiceTracker /** * Stop the tracker with the provided track id. http://git-wip-us.apache.org/repos/asf/celix/blob/626687fe/framework/include/celix_service_factory.h ---------------------------------------------------------------------- diff --git a/framework/include/celix_service_factory.h b/framework/include/celix_service_factory.h new file mode 100644 index 0000000..4373db6 --- /dev/null +++ b/framework/include/celix_service_factory.h @@ -0,0 +1,43 @@ +/** + *Licensed to the Apache Software Foundation (ASF) under one + *or more contributor license agreements. See the NOTICE file + *distributed with this work for additional information + *regarding copyright ownership. The ASF licenses this file + *to you under the Apache License, Version 2.0 (the + *"License"); you may not use this file except in compliance + *with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + *Unless required by applicable law or agreed to in writing, + *software distributed under the License is distributed on an + *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + *specific language governing permissions and limitations + *under the License. + */ +#ifndef CELIX_SERVICE_FACTORY_H_ +#define CELIX_SERVICE_FACTORY_H_ + +#include "properties.h" +#include "bundle.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct celix_service_factory celix_service_factory_t; + +struct celix_service_factory { + void *handle; + + void* (*getService)(void *handle, const celix_bundle_t *requestingBundle, const celix_properties_t *svcProperties); + + void (*ungetService)(void *handle, const celix_bundle_t *requestingBundle, const celix_properties_t *svcProperties); +}; + +#ifdef __cplusplus +} +#endif + +#endif /* CELIX_SERVICE_FACTORY_H_ */ http://git-wip-us.apache.org/repos/asf/celix/blob/626687fe/framework/include/celix_types.h ---------------------------------------------------------------------- diff --git a/framework/include/celix_types.h b/framework/include/celix_types.h index 7846c1c..6e02c63 100644 --- a/framework/include/celix_types.h +++ b/framework/include/celix_types.h @@ -48,4 +48,6 @@ typedef struct dm_component_struct dm_component_t; typedef struct dm_service_dependency *dm_service_dependency_pt; typedef struct dm_service_dependency dm_service_dependency_t; +typedef struct service_factory *service_factory_pt; //deprecated + #endif //CELIX_CELIX_TYPES_H http://git-wip-us.apache.org/repos/asf/celix/blob/626687fe/framework/include/service_factory.h ---------------------------------------------------------------------- diff --git a/framework/include/service_factory.h b/framework/include/service_factory.h index 84e383a..80230d1 100644 --- a/framework/include/service_factory.h +++ b/framework/include/service_factory.h @@ -16,26 +16,10 @@ *specific language governing permissions and limitations *under the License. */ -/* - * service_factory.h - * - * \date Jun 26, 2011 - * \author <a href="mailto:[email protected]">Apache Celix Project Team</a> - * \copyright Apache License, Version 2.0 - */ - #ifndef SERVICE_FACTORY_H_ #define SERVICE_FACTORY_H_ -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct service_factory service_factory_t; -typedef service_factory_t *service_factory_pt; -#ifdef __cplusplus -} -#endif +#include "celix_types.h" #include "celix_errno.h" #include "service_registration.h" #include "bundle.h" @@ -47,10 +31,10 @@ extern "C" { struct service_factory { void *handle; - celix_status_t (*getService)(void *handle, bundle_pt bundle, service_registration_pt registration, void **service); + celix_status_t (*getService)(void *handle, celix_bundle_t *bnd, service_registration_pt registration, void **service); celix_status_t - (*ungetService)(void *handle, bundle_pt bundle, service_registration_pt registration, void **service); + (*ungetService)(void *handle, celix_bundle_t *bnd, service_registration_pt registration, void **service); }; #ifdef __cplusplus http://git-wip-us.apache.org/repos/asf/celix/blob/626687fe/framework/include/service_registry.h ---------------------------------------------------------------------- diff --git a/framework/include/service_registry.h b/framework/include/service_registry.h index 9a2ec48..9ca4a59 100644 --- a/framework/include/service_registry.h +++ b/framework/include/service_registry.h @@ -27,7 +27,8 @@ #ifndef SERVICE_REGISTRY_H_ #define SERVICE_REGISTRY_H_ -typedef struct serviceRegistry * service_registry_pt; +typedef struct celix_serviceRegistry * service_registry_pt; +typedef struct celix_serviceRegistry celix_service_registry_t; #include "properties.h" #include "filter.h" @@ -35,6 +36,8 @@ typedef struct serviceRegistry * service_registry_pt; #include "service_event.h" #include "array_list.h" #include "service_registration.h" +#include "celix_service_factory.h" + #ifdef __cplusplus extern "C" { #endif @@ -96,6 +99,15 @@ celix_status_t serviceRegistry_servicePropertiesModified(service_registry_pt registry, service_registration_pt registration, properties_pt oldprops); +celix_status_t +celix_serviceRegistry_registerServiceFactory( + celix_service_registry_t *reg, + const celix_bundle_t *bnd, + const char *serviceName, + celix_service_factory_t *factory, + celix_properties_t* props, + service_registration_t **registration); + #ifdef __cplusplus } #endif http://git-wip-us.apache.org/repos/asf/celix/blob/626687fe/framework/private/mock/bundle_context_mock.c ---------------------------------------------------------------------- diff --git a/framework/private/mock/bundle_context_mock.c b/framework/private/mock/bundle_context_mock.c index 8225580..749e3ca 100644 --- a/framework/private/mock/bundle_context_mock.c +++ b/framework/private/mock/bundle_context_mock.c @@ -326,3 +326,24 @@ void celix_bundleContext_useServicesWithOptions( ->withPointerParameters("ctx", ctx) ->withConstPointerParameters("opts", opts); } + +long celix_bundleContext_registerServiceFactory(celix_bundle_context_t *ctx, const char *serviceName, celix_service_factory_t *factory, const char *serviceVersion, celix_properties_t *props) { + mock_c()->actualCall("celix_bundleContext_registerServiceFactory") + ->withPointerParameters("ctx", ctx) + ->withStringParameters("serviceName", serviceName) + ->withPointerParameters("factory", factory) + ->withStringParameters("serviceVersion", serviceVersion) + ->withPointerParameters("props", props); + return mock_c()->returnValue().value.longIntValue; +} + +long celix_bundleContext_registerServiceFactorForLang(celix_bundle_context_t *ctx, const char *serviceName, celix_service_factory_t *factory, const char *serviceVersion, const char *lang, celix_properties_t *props) { + mock_c()->actualCall("celix_bundleContext_registerServiceFactorForLang") + ->withPointerParameters("ctx", ctx) + ->withStringParameters("serviceName", serviceName) + ->withPointerParameters("factory", factory) + ->withStringParameters("serviceVersion", serviceVersion) + ->withStringParameters("lang", lang) + ->withPointerParameters("props", props); + return mock_c()->returnValue().value.longIntValue; +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/celix/blob/626687fe/framework/private/mock/framework_mock.c ---------------------------------------------------------------------- diff --git a/framework/private/mock/framework_mock.c b/framework/private/mock/framework_mock.c index d718ade..7bbd752 100644 --- a/framework/private/mock/framework_mock.c +++ b/framework/private/mock/framework_mock.c @@ -335,4 +335,12 @@ void celix_framework_useBundle(framework_t *fw, long bundleId, void *callbackHan ->withPointerParameters("use", use); } - +service_registration_t* celix_framework_registerServiceFactory(framework_t *fw , const celix_bundle_t *bnd, const char* serviceName, celix_service_factory_t *factory, celix_properties_t *properties) { + mock_c()->actualCall("celix_framework_registerServiceFactory") + ->withPointerParameters("fw", fw) + ->withConstPointerParameters("bnd", bnd) + ->withStringParameters("serviceName", serviceName) + ->withPointerParameters("factory", factory) + ->withPointerParameters("properties", properties); + return mock_c()->returnValue().value.pointerValue; +} http://git-wip-us.apache.org/repos/asf/celix/blob/626687fe/framework/private/mock/service_registration_mock.c ---------------------------------------------------------------------- diff --git a/framework/private/mock/service_registration_mock.c b/framework/private/mock/service_registration_mock.c index 4bbf0c8..69be7eb 100644 --- a/framework/private/mock/service_registration_mock.c +++ b/framework/private/mock/service_registration_mock.c @@ -145,3 +145,20 @@ long serviceRegistration_getServiceId(service_registration_t *registration) { return mock_c()->returnValue().value.longIntValue; } +service_registration_t* celix_serviceRegistration_createServiceFactory( + registry_callback_t callback, + const celix_bundle_t *bnd, + const char *serviceName, + long svcId, + celix_service_factory_t* factory, + celix_properties_t *props) { + mock_c()->actualCall("celix_serviceRegistration_createServiceFactory") + ->withParameterOfType("registry_callback_t", "callback", &callback) + ->withConstPointerParameters("bnd", bnd) + ->withStringParameters("serviceName", serviceName) + ->withUnsignedLongIntParameters("svcId", svcId) + ->withPointerParameters("factory", (void*) factory) + ->withPointerParameters("props", props); + return mock_c()->returnValue().value.pointerValue; +} + http://git-wip-us.apache.org/repos/asf/celix/blob/626687fe/framework/private/mock/service_registry_mock.c ---------------------------------------------------------------------- diff --git a/framework/private/mock/service_registry_mock.c b/framework/private/mock/service_registry_mock.c index 60b8032..9942818 100644 --- a/framework/private/mock/service_registry_mock.c +++ b/framework/private/mock/service_registry_mock.c @@ -164,3 +164,21 @@ celix_status_t serviceRegistry_clearServiceRegistrations(service_registry_pt reg ->withPointerParameters("bundle", bundle); return mock_c()->returnValue().value.intValue; } + +celix_status_t +celix_serviceRegistry_registerServiceFactory( + celix_service_registry_t *reg, + const celix_bundle_t *bnd, + const char *serviceName, + celix_service_factory_t *factory, + celix_properties_t* props, + service_registration_t **registration) { + mock_c()->actualCall("celix_serviceRegistry_registerServiceFactory") + ->withPointerParameters("reg", reg) + ->withConstPointerParameters("bnd", bnd) + ->withStringParameters("serviceName", serviceName) + ->withPointerParameters("factory", factory) + ->withPointerParameters("props", props) + ->withOutputParameter("registration", registration); + return mock_c()->returnValue().value.intValue; +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/celix/blob/626687fe/framework/private/test/service_registration_test.cpp ---------------------------------------------------------------------- diff --git a/framework/private/test/service_registration_test.cpp b/framework/private/test/service_registration_test.cpp index da4420d..68986bf 100644 --- a/framework/private/test/service_registration_test.cpp +++ b/framework/private/test/service_registration_test.cpp @@ -111,8 +111,9 @@ TEST(service_registration, create) { UNSIGNED_LONGS_EQUAL(serviceId, registration->serviceId); LONGS_EQUAL(0, registration->isUnregistering); - LONGS_EQUAL(0, registration->isServiceFactory); - POINTERS_EQUAL(NULL, registration->serviceFactory); + LONGS_EQUAL(CELIX_PLAIN_SERVICE, registration->svcType); + POINTERS_EQUAL(NULL, registration->deprecatedFactory); + POINTERS_EQUAL(NULL, registration->factory); POINTERS_EQUAL(NULL, registration->services); LONGS_EQUAL(0, registration->nrOfServices); @@ -143,8 +144,8 @@ TEST(service_registration, createServiceFactory) { POINTERS_EQUAL(service, registration->svcObj); UNSIGNED_LONGS_EQUAL(serviceId, registration->serviceId); LONGS_EQUAL(0, registration->isUnregistering); - LONGS_EQUAL(1, registration->isServiceFactory); - POINTERS_EQUAL(service, registration->serviceFactory); + LONGS_EQUAL(CELIX_DEPRECATED_FACTORY_SERVICE, registration->svcType); + POINTERS_EQUAL(service, registration->deprecatedFactory); POINTERS_EQUAL(NULL, registration->services); LONGS_EQUAL(0, registration->nrOfServices); http://git-wip-us.apache.org/repos/asf/celix/blob/626687fe/framework/src/bundle_context.c ---------------------------------------------------------------------- diff --git a/framework/src/bundle_context.c b/framework/src/bundle_context.c index 5a9bbd1..7d5dea9 100644 --- a/framework/src/bundle_context.c +++ b/framework/src/bundle_context.c @@ -426,30 +426,25 @@ celix_status_t bundleContext_getPropertyWithDefault(bundle_context_pt context, c long celix_bundleContext_registerService(bundle_context_t *ctx, const char *serviceName, void *svc, const char *serviceVersion, properties_t *properties) { - return celix_bundleContext_registerServiceForLang(ctx, serviceName, svc, serviceVersion, CELIX_FRAMEWORK_SERVICE_C_LANGUAGE, properties); + return celix_bundleContext_registerServiceForLang(ctx, serviceName, svc, serviceVersion, NULL, properties); } long celix_bundleContext_registerServiceForLang(bundle_context_t *ctx, const char *serviceName, void *svc, const char *serviceVersion, const char* lang, properties_t *properties) { long svcId = -1; + service_registration_t *reg = NULL; if (properties == NULL) { properties = properties_create(); } - service_registration_t *reg = NULL; if (serviceVersion != NULL) { properties_set(properties, CELIX_FRAMEWORK_SERVICE_VERSION, serviceVersion); } - if (serviceName != NULL && lang != NULL) { - properties_set(properties, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang); + if (serviceName != NULL) { + properties_set(properties, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang == NULL ? CELIX_FRAMEWORK_SERVICE_C_LANGUAGE : lang); bundleContext_registerService(ctx, serviceName, svc, properties, ®); svcId = serviceRegistration_getServiceId(reg); //save to call with NULL } else { - if (serviceName == NULL) { - framework_logIfError(logger, CELIX_ILLEGAL_ARGUMENT, NULL, "Required serviceName argument is NULL"); - } - if (lang == NULL) { - framework_logIfError(logger, CELIX_ILLEGAL_ARGUMENT, NULL, "Required lang argument is NULL"); - } + framework_logIfError(logger, CELIX_ILLEGAL_ARGUMENT, NULL, "Required serviceName argument is NULL"); } if (svcId < 0) { properties_destroy(properties); @@ -812,4 +807,28 @@ long celix_bundleContext_trackServicesWithOptions(bundle_context_t *ctx, const c celixThreadMutex_unlock(&ctx->mutex); } return trackerId; +} + +long celix_bundleContext_registerServiceFactory(celix_bundle_context_t *ctx, const char *serviceName, celix_service_factory_t *factory, const char *serviceVersion, celix_properties_t *props) { + return celix_bundleContext_registerServiceFactorForLang(ctx, serviceName, factory, serviceVersion, NULL, props); +} + +long celix_bundleContext_registerServiceFactorForLang(celix_bundle_context_t *ctx, const char *serviceName, celix_service_factory_t *factory, const char *serviceVersion, const char *lang, celix_properties_t *props) { + if (props == NULL) { + props = celix_properties_create(); + } + if (serviceVersion != NULL) { + celix_properties_set(props, CELIX_FRAMEWORK_SERVICE_VERSION, serviceVersion); + } + celix_properties_set(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, lang == NULL ? CELIX_FRAMEWORK_SERVICE_C_LANGUAGE : lang); + service_registration_t *reg = celix_framework_registerServiceFactory(ctx->framework, ctx->bundle, serviceName, factory, props); + long facId = serviceRegistration_getServiceId(reg); //save to call with NULL + if (facId < 0) { + properties_destroy(props); + } else { + celixThreadMutex_lock(&ctx->mutex); + arrayList_add(ctx->svcRegistrations, reg); + celixThreadMutex_unlock(&ctx->mutex); + } + return facId; } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/celix/blob/626687fe/framework/src/framework.c ---------------------------------------------------------------------- diff --git a/framework/src/framework.c b/framework/src/framework.c index b6cb825..952392c 100644 --- a/framework/src/framework.c +++ b/framework/src/framework.c @@ -2781,4 +2781,22 @@ void celix_framework_useBundle(framework_t *fw, long bundleId, void *callbackHan } //TODO unlock } +} + +service_registration_t* celix_framework_registerServiceFactory(framework_t *fw , const celix_bundle_t *bnd, const char* serviceName, celix_service_factory_t *factory, celix_properties_t *properties) { + const char *error = NULL; + celix_status_t status = CELIX_SUCCESS; + service_registration_t *reg = NULL; + if (serviceName != NULL && factory != NULL) { + status = framework_acquireBundleLock(fw, (celix_bundle_t*)bnd, OSGI_FRAMEWORK_BUNDLE_STARTING|OSGI_FRAMEWORK_BUNDLE_ACTIVE); + status = CELIX_DO_IF(status, celix_serviceRegistry_registerServiceFactory(fw->registry, bnd, serviceName, factory, properties, ®)); + if (!framework_releaseBundleLock(fw, (celix_bundle_t*)bnd)) { + status = CELIX_ILLEGAL_STATE; + error = "Could not release bundle lock"; + } + } + + framework_logIfError(fw->logger, status, error, "Cannot register service factory: %s", serviceName); + + return reg; } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/celix/blob/626687fe/framework/src/framework_private.h ---------------------------------------------------------------------- diff --git a/framework/src/framework_private.h b/framework/src/framework_private.h index 66c1125..ab0a940 100644 --- a/framework/src/framework_private.h +++ b/framework/src/framework_private.h @@ -65,7 +65,7 @@ struct framework { celix_thread_mutex_t bundleListenerLock; long nextBundleId; - struct serviceRegistry * registry; + celix_service_registry_t *registry; bundle_cache_pt cache; celix_thread_cond_t shutdownGate; @@ -158,5 +158,6 @@ FRAMEWORK_EXPORT bundle_pt framework_getBundleById(framework_pt framework, long void celix_framework_useBundles(framework_t *fw, void *callbackHandle, void(*use)(void *handle, const bundle_t *bnd)); void celix_framework_useBundle(framework_t *fw, long bundleId, void *callbackHandle, void(*use)(void *handle, const bundle_t *bnd)); +service_registration_t* celix_framework_registerServiceFactory(framework_t *fw , const celix_bundle_t *bnd, const char* serviceName, celix_service_factory_t *factory, celix_properties_t *properties); #endif /* FRAMEWORK_PRIVATE_H_ */ http://git-wip-us.apache.org/repos/asf/celix/blob/626687fe/framework/src/service_registration.c ---------------------------------------------------------------------- diff --git a/framework/src/service_registration.c b/framework/src/service_registration.c index fe25214..b3f45b2 100644 --- a/framework/src/service_registration.c +++ b/framework/src/service_registration.c @@ -33,7 +33,7 @@ static celix_status_t serviceRegistration_initializeProperties(service_registration_pt registration, properties_pt properties); static celix_status_t serviceRegistration_createInternal(registry_callback_t callback, bundle_pt bundle, const char* serviceName, unsigned long serviceId, - const void * serviceObject, properties_pt dictionary, bool isFactory, service_registration_pt *registration); + const void * serviceObject, properties_pt dictionary, enum celix_service_type svcType, service_registration_pt *registration); static celix_status_t serviceRegistration_destroy(service_registration_pt registration); service_registration_pt serviceRegistration_create(registry_callback_t callback, bundle_pt bundle, const char* serviceName, unsigned long serviceId, const void * serviceObject, properties_pt dictionary) { @@ -49,25 +49,25 @@ service_registration_pt serviceRegistration_createServiceFactory(registry_callba } static celix_status_t serviceRegistration_createInternal(registry_callback_t callback, bundle_pt bundle, const char* serviceName, unsigned long serviceId, - const void * serviceObject, properties_pt dictionary, bool isFactory, service_registration_pt *out) { - celix_status_t status = CELIX_SUCCESS; + const void * serviceObject, properties_pt dictionary, enum celix_service_type svcType, service_registration_pt *out) { + celix_status_t status = CELIX_SUCCESS; service_registration_pt reg = calloc(1, sizeof(*reg)); if (reg) { reg->callback = callback; reg->services = NULL; reg->nrOfServices = 0; - reg->isServiceFactory = isFactory; + reg->svcType = svcType; reg->className = strndup(serviceName, 1024*10); reg->bundle = bundle; reg->refCount = 1; - reg->serviceId = serviceId; - reg->svcObj = serviceObject; - if (isFactory) { - reg->serviceFactory = (service_factory_pt) reg->svcObj; - } else { - reg->serviceFactory = NULL; + reg->svcObj = serviceObject; + + if (svcType == CELIX_DEPRECATED_FACTORY_SERVICE) { + reg->deprecatedFactory = (service_factory_pt) reg->svcObj; + } else if (svcType == CELIX_FACTORY_SERVICE) { + reg->factory = (celix_service_factory_t*) reg->svcObj; } reg->isUnregistering = false; @@ -190,29 +190,29 @@ celix_status_t serviceRegistration_unregister(service_registration_pt registrati } celix_status_t serviceRegistration_getService(service_registration_pt registration, bundle_pt bundle, const void** service) { - int status = CELIX_SUCCESS; celixThreadRwlock_readLock(®istration->lock); - if (registration->isServiceFactory) { - service_factory_pt factory = (void*) registration->serviceFactory; - /*NOTE the service argument of the service_factory should be const void**. - To ensure backwards compatability a cast is made instead. - */ - status = factory->getService(factory->handle, bundle, registration, (void**) service); - } else { + if (registration->svcType == CELIX_DEPRECATED_FACTORY_SERVICE) { + service_factory_pt factory = registration->deprecatedFactory; + factory->getService(factory->handle, bundle, registration, (void **) service); + } else if (registration->svcType == CELIX_FACTORY_SERVICE) { + celix_service_factory_t *fac = registration->factory; + *service = fac->getService(fac->handle, bundle, registration->properties); + } else { //plain service (*service) = registration->svcObj; } celixThreadRwlock_unlock(®istration->lock); - return status; + + return CELIX_SUCCESS; } celix_status_t serviceRegistration_ungetService(service_registration_pt registration, bundle_pt bundle, const void** service) { celixThreadRwlock_readLock(®istration->lock); - if (registration->isServiceFactory) { - service_factory_pt factory = (void*) registration->serviceFactory; - /*NOTE the service argument of the service_factory should be const void**. - To ensure backwards compatibility a cast is made instead. - */ + if (registration->svcType == CELIX_DEPRECATED_FACTORY_SERVICE) { + service_factory_pt factory = registration->deprecatedFactory; factory->ungetService(factory->handle, bundle, registration, (void**) service); + } else if (registration->svcType == CELIX_FACTORY_SERVICE) { + celix_service_factory_t *fac = registration->factory; + fac->ungetService(fac->handle, bundle, registration->properties); } celixThreadRwlock_unlock(®istration->lock); return CELIX_SUCCESS; @@ -299,3 +299,16 @@ long serviceRegistration_getServiceId(service_registration_t *registration) { } return svcId; } + + +service_registration_t* celix_serviceRegistration_createServiceFactory( + registry_callback_t callback, + const celix_bundle_t *bnd, + const char *serviceName, + long svcId, + celix_service_factory_t* factory, + celix_properties_t *props) { + service_registration_pt registration = NULL; + serviceRegistration_createInternal(callback, (celix_bundle_t*)bnd, serviceName, svcId, factory, props, CELIX_FACTORY_SERVICE, ®istration); + return registration; +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/celix/blob/626687fe/framework/src/service_registration_private.h ---------------------------------------------------------------------- diff --git a/framework/src/service_registration_private.h b/framework/src/service_registration_private.h index ca0cb67..598e4c9 100644 --- a/framework/src/service_registration_private.h +++ b/framework/src/service_registration_private.h @@ -31,19 +31,26 @@ #include "registry_callback_private.h" #include "service_registration.h" +enum celix_service_type { + CELIX_PLAIN_SERVICE, + CELIX_FACTORY_SERVICE, + CELIX_DEPRECATED_FACTORY_SERVICE +}; + struct serviceRegistration { registry_callback_t callback; char * className; bundle_pt bundle; properties_pt properties; - const void * svcObj; unsigned long serviceId; bool isUnregistering; - bool isServiceFactory; - const void *serviceFactory; + enum celix_service_type svcType; + const void * svcObj; + service_factory_pt deprecatedFactory; + celix_service_factory_t *factory; struct service *services; int nrOfServices; @@ -68,4 +75,13 @@ celix_status_t serviceRegistration_ungetService(service_registration_pt registra celix_status_t serviceRegistration_getBundle(service_registration_pt registration, bundle_pt *bundle); celix_status_t serviceRegistration_getServiceName(service_registration_pt registration, const char **serviceName); + +service_registration_t* celix_serviceRegistration_createServiceFactory( + registry_callback_t callback, + const celix_bundle_t *bnd, + const char *serviceName, + long svcId, + celix_service_factory_t* factory, + celix_properties_t *props); + #endif /* SERVICE_REGISTRATION_PRIVATE_H_ */ http://git-wip-us.apache.org/repos/asf/celix/blob/626687fe/framework/src/service_registry.c ---------------------------------------------------------------------- diff --git a/framework/src/service_registry.c b/framework/src/service_registry.c index 65c1914..1493525 100644 --- a/framework/src/service_registry.c +++ b/framework/src/service_registry.c @@ -41,7 +41,7 @@ #define CHECK_DELETED_REFERENCES false #endif -static celix_status_t serviceRegistry_registerServiceInternal(service_registry_pt registry, bundle_pt bundle, const char* serviceName, const void * serviceObject, properties_pt dictionary, bool isFactory, service_registration_pt *registration); +static celix_status_t serviceRegistry_registerServiceInternal(service_registry_pt registry, bundle_pt bundle, const char* serviceName, const void * serviceObject, properties_pt dictionary, enum celix_service_type svcType, service_registration_pt *registration); static celix_status_t serviceRegistry_addHooks(service_registry_pt registry, const char* serviceName, const void *serviceObject, service_registration_pt registration); static celix_status_t serviceRegistry_removeHook(service_registry_pt registry, service_registration_pt registration); static void serviceRegistry_logWarningServiceReferenceUsageCount(service_registry_pt registry, bundle_pt bundle, service_reference_pt ref, size_t usageCount, size_t refCount); @@ -154,12 +154,16 @@ celix_status_t serviceRegistry_registerServiceFactory(service_registry_pt regist return serviceRegistry_registerServiceInternal(registry, bundle, serviceName, (const void *) factory, dictionary, true, registration); } -static celix_status_t serviceRegistry_registerServiceInternal(service_registry_pt registry, bundle_pt bundle, const char* serviceName, const void* serviceObject, properties_pt dictionary, bool isFactory, service_registration_pt *registration) { +static celix_status_t serviceRegistry_registerServiceInternal(service_registry_pt registry, bundle_pt bundle, const char* serviceName, const void * serviceObject, properties_pt dictionary, enum celix_service_type svcType, service_registration_pt *registration) { array_list_pt regs; - if (isFactory) { - *registration = serviceRegistration_createServiceFactory(registry->callback, bundle, serviceName, ++registry->currentServiceId, serviceObject, dictionary); - } else { + if (svcType == CELIX_DEPRECATED_FACTORY_SERVICE) { + *registration = serviceRegistration_createServiceFactory(registry->callback, bundle, serviceName, + ++registry->currentServiceId, serviceObject, + dictionary); + } else if (svcType == CELIX_FACTORY_SERVICE) { + *registration = celix_serviceRegistration_createServiceFactory(registry->callback, bundle, serviceName, ++registry->currentServiceId, (celix_service_factory_t*)serviceObject, dictionary); + } else { //plain *registration = serviceRegistration_create(registry->callback, bundle, serviceName, ++registry->currentServiceId, serviceObject, dictionary); } @@ -800,3 +804,14 @@ static celix_status_t serviceRegistry_getUsingBundles(service_registry_pt regist return status; } + +celix_status_t +celix_serviceRegistry_registerServiceFactory( + celix_service_registry_t *reg, + const celix_bundle_t *bnd, + const char *serviceName, + celix_service_factory_t *factory, + celix_properties_t* props, + service_registration_t **registration) { + return serviceRegistry_registerServiceInternal(reg, (celix_bundle_t*)bnd, serviceName, (const void *) factory, props, CELIX_FACTORY_SERVICE, registration); +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/celix/blob/626687fe/framework/src/service_registry_private.h ---------------------------------------------------------------------- diff --git a/framework/src/service_registry_private.h b/framework/src/service_registry_private.h index d68fe11..1bd0066 100644 --- a/framework/src/service_registry_private.h +++ b/framework/src/service_registry_private.h @@ -31,7 +31,7 @@ #include "registry_callback_private.h" #include "service_registry.h" -struct serviceRegistry { +struct celix_serviceRegistry { framework_pt framework; registry_callback_t callback; http://git-wip-us.apache.org/repos/asf/celix/blob/626687fe/framework/tst/bundle_context_services_test.cpp ---------------------------------------------------------------------- diff --git a/framework/tst/bundle_context_services_test.cpp b/framework/tst/bundle_context_services_test.cpp index 790cbd2..2597ece 100644 --- a/framework/tst/bundle_context_services_test.cpp +++ b/framework/tst/bundle_context_services_test.cpp @@ -26,11 +26,13 @@ #include <CppUTest/CommandLineTestRunner.h> #include <zconf.h> #include <string.h> +#include <map> #include "constants.h" #include "bundle.h" #include "properties.h" #include "celix_framework_factory.h" +#include "celix_service_factory.h" TEST_GROUP(CelixBundleContextServicesTests) { @@ -582,3 +584,47 @@ TEST(CelixBundleContextServicesTests, servicesTrackerSetTest) { } //TODO test tracker with options for properties & service owners + + +TEST(CelixBundleContextServicesTests, serviceFactoryTest) { + struct calc { + int (*calc)(int); + }; + auto name = "CALC"; + auto version = "1.0.0"; + + + int count = 0; + celix_service_factory_t fac; + memset(&fac, 0, sizeof(fac)); + fac.handle = (void*)&count; + fac.getService = [](void *handle, const celix_bundle_t *, const celix_properties_t *) -> void* { + auto *c = (int *)handle; + *c += 1; + static struct calc svc{}; //normally a service per bundle + svc.calc = [](int arg) { return arg * 42; }; + return &svc; + }; + fac.ungetService = [](void *handle, const celix_bundle_t *, const celix_properties_t *) { + auto *c = (int *)handle; + *c += 1; + }; + + long facId = celix_bundleContext_registerServiceFactory(ctx, name, &fac, version, NULL); + CHECK_TRUE(facId >= 0); + + + int result = -1; + bool called = celix_bundleContext_useService(ctx, name, &result, [](void *handle, void* svc) { + auto *r = (int *)(handle); + auto *calc = (struct calc*)svc; + *r = calc->calc(2); + }); + CHECK_TRUE(called); + CHECK_EQUAL(84, result); + CHECK_EQUAL(2, count); //expecting getService & unGetService to be called during the useService call. + + + celix_bundleContext_unregisterService(ctx, facId); +} +
