This is an automated email from the ASF dual-hosted git repository. pnoltes pushed a commit to branch feature/update_standard_service_properties in repository https://gitbox.apache.org/repos/asf/celix.git
commit 4612552589644f612b674cdf67ec414a89c8f80f Author: Pepijn Noltes <[email protected]> AuthorDate: Fri Jul 30 16:34:36 2021 +0200 Adds support for the service.bundleid and service.scope framework props --- .../gtest/src/CxxBundleContextTestSuite.cc | 45 +++++++++++ libs/framework/include/celix/Constants.h | 41 ++++++++-- libs/framework/include/celix_constants.h | 90 +++++++++++++++++----- libs/framework/src/service_registry.c | 6 ++ 4 files changed, 157 insertions(+), 25 deletions(-) diff --git a/libs/framework/gtest/src/CxxBundleContextTestSuite.cc b/libs/framework/gtest/src/CxxBundleContextTestSuite.cc index 8f059fd..52654c4 100644 --- a/libs/framework/gtest/src/CxxBundleContextTestSuite.cc +++ b/libs/framework/gtest/src/CxxBundleContextTestSuite.cc @@ -20,6 +20,7 @@ #include <gtest/gtest.h> #include <atomic> +#include <search.h> #include "celix/BundleContext.h" @@ -609,4 +610,48 @@ TEST_F(CxxBundleContextTestSuite, WaitForAllEvents) { ctx->waitIfAbleForAllEvents(); svcId = ctx->findService<TestInterface>(); EXPECT_EQ(svcId, -1L); +} + + +TEST_F(CxxBundleContextTestSuite, CheckStandardServiceProperties) { + /* + * OSGi 7 specifies the following service properties which must be set by the framework: + * - objectClass (CELIX_FRAMEWORK_SERVICE_NAME) + * - service.id (CELIX_FRAMEWORK_SERVICE_ID) + * - service.bundleid (CELIX_FRAMEWORK_SERVICE_BUNDLE_ID) + * - service.scope (CELIX_FRAMEWORK_SERVICE_SCOPE) + */ + + auto svcReg = ctx->registerService<TestInterface>(std::make_shared<TestImplementation>()).build(); + bool called = ctx->useService<TestInterface>() + .addUseCallback([](TestInterface& /*svc*/, const celix::Properties& props) { + EXPECT_FALSE(props.get(celix::SERVICE_NAME).empty()); + EXPECT_GE(props.getAsLong(celix::SERVICE_BUNDLE_ID, -1), 0); + EXPECT_EQ(props.get(celix::SERVICE_SCOPE), std::string{celix::SERVICE_SCOPE_SINGLETON}); + }) + .build(); + EXPECT_TRUE(called); + + //note using c api, because C++ api does not yet support registering svc factories + celix_service_factory_t factory{nullptr, nullptr, nullptr}; + factory.getService = [](void */*handle*/, const celix_bundle_t */*requestingBundle*/, const celix_properties_t */*svcProperties*/) -> void* { + //dummy svc + return (void*)0x42; + }; + factory.ungetService = [](void */*handle*/, const celix_bundle_t */*requestingBundle*/, const celix_properties_t */*svcProperties*/) { + //nop + }; + auto svcId = celix_bundleContext_registerServiceFactory(ctx->getCBundleContext(), &factory, "TestInterfaceFactory", nullptr); + EXPECT_GE(svcId, 0); + + called = ctx->useService<TestInterface>("TestInterfaceFactory") + .addUseCallback([](TestInterface& /*svc*/, const celix::Properties& props) { + EXPECT_FALSE(props.get(celix::SERVICE_NAME).empty()); + EXPECT_GE(props.getAsLong(celix::SERVICE_BUNDLE_ID, -1), 0); + EXPECT_EQ(props.get(celix::SERVICE_SCOPE), std::string{celix::SERVICE_SCOPE_BUNDLE}); + }) + .build(); + EXPECT_TRUE(called); + + celix_bundleContext_unregisterService(ctx->getCBundleContext(), svcId); } \ No newline at end of file diff --git a/libs/framework/include/celix/Constants.h b/libs/framework/include/celix/Constants.h index 084602d..8f84ccb 100644 --- a/libs/framework/include/celix/Constants.h +++ b/libs/framework/include/celix/Constants.h @@ -34,7 +34,7 @@ namespace celix { * * This property is set by the Celix framework when a service is registered. */ - constexpr const char * const SERVICE_NAME = OSGI_FRAMEWORK_OBJECTCLASS; + constexpr const char * const SERVICE_NAME = CELIX_FRAMEWORK_SERVICE_NAME; /** * @brief Service property (named "service.id") identifying a service's registration number (of type long). @@ -43,7 +43,36 @@ namespace celix { * The Celix framework assigns a unique value that is larger than all previously assigned values since the * Celix framework was started. */ - constexpr const char * const SERVICE_ID = OSGI_FRAMEWORK_SERVICE_ID; + constexpr const char * const SERVICE_ID = CELIX_FRAMEWORK_SERVICE_ID; + + /** + * @brief Service property (named service.bundleid) identifying the bundle id of the bundle registering the service. + * + * This property is set by the Celix framework when a service is registered. The value of this property must be of type Long. + */ + constexpr const char * const SERVICE_BUNDLE_ID = CELIX_FRAMEWORK_SERVICE_BUNDLE_ID; + + /** + * @brief Service property (named service.scope) identifying a service's scope. + * + * This property is set by the Framework when a service is registered. + * If the registered object implements service factory, then the value of this service property will be + * CELIX_FRAMEWORK_SERVICE_SCOPE_BUNDLE. + * Otherwise, the value of this service property will be CELIX_FRAMEWORK_SERVICE_SCOPE_SINGLETON. + * + * @warning Note that the scope "prototype" is not supported in Celix. + */ + constexpr const char * const SERVICE_SCOPE = CELIX_FRAMEWORK_SERVICE_SCOPE; + + /** + * @brief Service scope is singleton. All bundles using the service receive the same service object. + */ + constexpr const char * const SERVICE_SCOPE_SINGLETON = CELIX_FRAMEWORK_SERVICE_SCOPE_SINGLETON; + + /** + * @brief Service scope is bundle. Each bundle using the service receives a customized service object. + */ + constexpr const char * const SERVICE_SCOPE_BUNDLE = CELIX_FRAMEWORK_SERVICE_SCOPE_BUNDLE; /** * @brief Service property (named "service.ranking") identifying a service's ranking number (of type long). @@ -59,7 +88,7 @@ namespace celix { * The default ranking is 0. A service with a ranking of LONG_MAX is very likely to be returned as the default * service, whereas a service with a ranking of LONG_MIN is very unlikely to be returned. */ - constexpr const char * const SERVICE_RANKING = OSGI_FRAMEWORK_SERVICE_RANKING; + constexpr const char * const SERVICE_RANKING = CELIX_FRAMEWORK_SERVICE_RANKING; /** * @brief Service property (named "service.version") specifying the optional version of a service. @@ -82,7 +111,7 @@ namespace celix { * * If not specified ".cache" is used. */ - constexpr const char * const FRAMEWORK_STORAGE = OSGI_FRAMEWORK_FRAMEWORK_STORAGE; + constexpr const char * const FRAMEWORK_STORAGE = CELIX_FRAMEWORK_FRAMEWORK_STORAGE; /** * @brief Celix framework environment property (named "org.osgi.framework.uuid") specifying the UUID for the @@ -93,7 +122,7 @@ namespace celix { * * @note The Celix framework expects framework UUIDs to be unique per process. */ - constexpr const char * const FRAMEWORK_UUID = OSGI_FRAMEWORK_FRAMEWORK_UUID; + constexpr const char * const FRAMEWORK_UUID = CELIX_FRAMEWORK_FRAMEWORK_UUID; /** * @brief Celix framework environment property (named "CELIX_FRAMEWORK_STATIC_EVENT_QUEUE_SIZE") which configures @@ -181,5 +210,5 @@ namespace celix { * * If not specified ".cache" is used. */ - constexpr const char * const FRAMEWORK_CACHE_DIR = OSGI_FRAMEWORK_FRAMEWORK_STORAGE; + constexpr const char * const FRAMEWORK_CACHE_DIR = CELIX_FRAMEWORK_FRAMEWORK_STORAGE; } \ No newline at end of file diff --git a/libs/framework/include/celix_constants.h b/libs/framework/include/celix_constants.h index c956493..b013317 100644 --- a/libs/framework/include/celix_constants.h +++ b/libs/framework/include/celix_constants.h @@ -27,12 +27,17 @@ extern "C" { #endif /** + * Collection of celix constants. Note that the CELIX_ macros are preferred over the OSGI_ variants. + */ + +/** * @brief Service property (named "objectClass") identifying the service name under which a service was registered * in the Celix framework. * * This property is set by the Celix framework when a service is registered. */ -#define OSGI_FRAMEWORK_OBJECTCLASS "objectClass" +#define CELIX_FRAMEWORK_SERVICE_NAME "objectClass" +#define OSGI_FRAMEWORK_OBJECTCLASS CELIX_FRAMEWORK_SERVICE_NAME /** * @brief Service property (named "service.id") identifying a service's registration number (of type long). @@ -41,9 +46,40 @@ extern "C" { * The Celix framework assigns a unique value that is larger than all previously assigned values since the * Celix framework was started. */ -#define OSGI_FRAMEWORK_SERVICE_ID "service.id" +#define CELIX_FRAMEWORK_SERVICE_ID "service.id" +#define OSGI_FRAMEWORK_SERVICE_ID CELIX_FRAMEWORK_SERVICE_ID + +/** + * @brief Service property (named service.bundleid) identifying the bundle id of the bundle registering the service. + * + * This property is set by the Celix framework when a service is registered. The value of this property must be of type Long. + */ +#define CELIX_FRAMEWORK_SERVICE_BUNDLE_ID "service.bundleid" + +/** + * @brief Service property (named service.scope) identifying a service's scope. + * + * This property is set by the Framework when a service is registered. + * If the registered object implements service factory, then the value of this service property will be + * CELIX_FRAMEWORK_SERVICE_SCOPE_BUNDLE. + * Otherwise, the value of this service property will be CELIX_FRAMEWORK_SERVICE_SCOPE_SINGLETON. + * + * @warning Note that the scope "prototype" is not supported in Celix. + */ +#define CELIX_FRAMEWORK_SERVICE_SCOPE "service.scope" + +/** + * @brief Service scope is singleton. All bundles using the service receive the same service object. + */ +#define CELIX_FRAMEWORK_SERVICE_SCOPE_SINGLETON "singleton" + +/** + * @brief Service scope is bundle. Each bundle using the service receives a customized service object. + */ +#define CELIX_FRAMEWORK_SERVICE_SCOPE_BUNDLE "bundle" -#define OSGI_FRAMEWORK_SERVICE_PID "service.pid" +#define CELIX_FRAMEWORK_SERVICE_PID "service.pid" +#define OSGI_FRAMEWORK_SERVICE_PID CELIX_FRAMEWORK_SERVICE_PID /** * @brief The bundle id (value 0) used to identify the Celix framework. @@ -64,7 +100,8 @@ extern "C" { * The default ranking is 0. A service with a ranking of LONG_MAX is very likely to be returned as the default * service, whereas a service with a ranking of LONG_MIN is very unlikely to be returned. */ -#define OSGI_FRAMEWORK_SERVICE_RANKING "service.ranking" +#define CELIX_FRAMEWORK_SERVICE_RANKING "service.ranking" +#define OSGI_FRAMEWORK_SERVICE_RANKING CELIX_FRAMEWORK_SERVICE_RANKING /** * @brief Service property (named "service.version") specifying the optional version of a service. @@ -89,23 +126,33 @@ extern "C" { #define CELIX_FRAMEWORK_SERVICE_CXX_LANGUAGE "C++" #define CELIX_FRAMEWORK_SERVICE_SHARED_LANGUAGE "shared" //e.g. marker services -#define OSGI_FRAMEWORK_BUNDLE_ACTIVATOR "Bundle-Activator" +#define CELIX_FRAMEWORK_BUNDLE_ACTIVATOR "Bundle-Activator" +#define OSGI_FRAMEWORK_BUNDLE_ACTIVATOR CELIX_FRAMEWORK_BUNDLE_ACTIVATOR -#define OSGI_FRAMEWORK_BUNDLE_ACTIVATOR_CREATE "celix_bundleActivator_create" -#define OSGI_FRAMEWORK_BUNDLE_ACTIVATOR_START "celix_bundleActivator_start" -#define OSGI_FRAMEWORK_BUNDLE_ACTIVATOR_STOP "celix_bundleActivator_stop" -#define OSGI_FRAMEWORK_BUNDLE_ACTIVATOR_DESTROY "celix_bundleActivator_destroy" +#define CELIX_FRAMEWORK_BUNDLE_ACTIVATOR_CREATE "celix_bundleActivator_create" +#define CELIX_FRAMEWORK_BUNDLE_ACTIVATOR_START "celix_bundleActivator_start" +#define CELIX_FRAMEWORK_BUNDLE_ACTIVATOR_STOP "celix_bundleActivator_stop" +#define CELIX_FRAMEWORK_BUNDLE_ACTIVATOR_DESTROY "celix_bundleActivator_destroy" +#define OSGI_FRAMEWORK_BUNDLE_ACTIVATOR_CREATE CELIX_FRAMEWORK_BUNDLE_ACTIVATOR_CREATE +#define OSGI_FRAMEWORK_BUNDLE_ACTIVATOR_START CELIX_FRAMEWORK_BUNDLE_ACTIVATOR_START +#define OSGI_FRAMEWORK_BUNDLE_ACTIVATOR_STOP CELIX_FRAMEWORK_BUNDLE_ACTIVATOR_STOP +#define OSGI_FRAMEWORK_BUNDLE_ACTIVATOR_DESTROY CELIX_FRAMEWORK_BUNDLE_ACTIVATOR_DESTROY #define OSGI_FRAMEWORK_DEPRECATED_BUNDLE_ACTIVATOR_CREATE "bundleActivator_create" #define OSGI_FRAMEWORK_DEPRECATED_BUNDLE_ACTIVATOR_START "bundleActivator_start" #define OSGI_FRAMEWORK_DEPRECATED_BUNDLE_ACTIVATOR_STOP "bundleActivator_stop" #define OSGI_FRAMEWORK_DEPRECATED_BUNDLE_ACTIVATOR_DESTROY "bundleActivator_destroy" -#define OSGI_FRAMEWORK_BUNDLE_SYMBOLICNAME "Bundle-SymbolicName" -#define OSGI_FRAMEWORK_BUNDLE_VERSION "Bundle-Version" -#define OSGI_FRAMEWORK_PRIVATE_LIBRARY "Private-Library" -#define OSGI_FRAMEWORK_EXPORT_LIBRARY "Export-Library" -#define OSGI_FRAMEWORK_IMPORT_LIBRARY "Import-Library" +#define CELIX_FRAMEWORK_BUNDLE_SYMBOLICNAME "Bundle-SymbolicName" +#define CELIX_FRAMEWORK_BUNDLE_VERSION "Bundle-Version" +#define CELIX_FRAMEWORK_PRIVATE_LIBRARY "Private-Library" +#define CELIX_FRAMEWORK_EXPORT_LIBRARY "Export-Library" +#define CELIX_FRAMEWORK_IMPORT_LIBRARY "Import-Library" +#define OSGI_FRAMEWORK_BUNDLE_SYMBOLICNAME CELIX_FRAMEWORK_BUNDLE_SYMBOLICNAME +#define OSGI_FRAMEWORK_BUNDLE_VERSION CELIX_FRAMEWORK_BUNDLE_VERSION +#define OSGI_FRAMEWORK_PRIVATE_LIBRARY CELIX_FRAMEWORK_PRIVATE_LIBRARY +#define OSGI_FRAMEWORK_EXPORT_LIBRARY CELIX_FRAMEWORK_EXPORT_LIBRARY +#define OSGI_FRAMEWORK_IMPORT_LIBRARY CELIX_FRAMEWORK_IMPORT_LIBRARY /** * @brief Celix framework environment property (named "org.osgi.framework.storage") specifying the cache @@ -113,11 +160,15 @@ extern "C" { * * If not specified ".cache" is used. */ -#define OSGI_FRAMEWORK_FRAMEWORK_STORAGE "org.osgi.framework.storage" +#define CELIX_FRAMEWORK_FRAMEWORK_STORAGE "org.osgi.framework.storage" +#define OSGI_FRAMEWORK_FRAMEWORK_STORAGE CELIX_FRAMEWORK_FRAMEWORK_STORAGE -#define OSGI_FRAMEWORK_STORAGE_USE_TMP_DIR "org.osgi.framework.storage.use.tmp.dir" -#define OSGI_FRAMEWORK_FRAMEWORK_STORAGE_CLEAN_NAME "org.osgi.framework.storage.clean" -#define OSGI_FRAMEWORK_FRAMEWORK_STORAGE_CLEAN_DEFAULT true +#define CELIX_FRAMEWORK_STORAGE_USE_TMP_DIR "org.osgi.framework.storage.use.tmp.dir" +#define CELIX_FRAMEWORK_FRAMEWORK_STORAGE_CLEAN_NAME "org.osgi.framework.storage.clean" +#define CELIX_FRAMEWORK_FRAMEWORK_STORAGE_CLEAN_DEFAULT true +#define OSGI_FRAMEWORK_STORAGE_USE_TMP_DIR CELIX_FRAMEWORK_STORAGE_USE_TMP_DIR +#define OSGI_FRAMEWORK_FRAMEWORK_STORAGE_CLEAN_NAME CELIX_FRAMEWORK_FRAMEWORK_STORAGE_CLEAN_NAME +#define OSGI_FRAMEWORK_FRAMEWORK_STORAGE_CLEAN_DEFAULT CELIX_FRAMEWORK_FRAMEWORK_STORAGE_CLEAN_DEFAULT /** * @brief Celix framework environment property (named "org.osgi.framework.uuid") specifying the UUID for the @@ -128,7 +179,8 @@ extern "C" { * * @note The Celix framework expects framework UUIDs to be unique per process. */ -#define OSGI_FRAMEWORK_FRAMEWORK_UUID "org.osgi.framework.uuid" +#define CELIX_FRAMEWORK_FRAMEWORK_UUID "org.osgi.framework.uuid" +#define OSGI_FRAMEWORK_FRAMEWORK_UUID CELIX_FRAMEWORK_FRAMEWORK_UUID /** * @brief Celix framework environment property (named "CELIX_BUNDLES_PATH") which specified a `;` separated diff --git a/libs/framework/src/service_registry.c b/libs/framework/src/service_registry.c index f73e48d..876965c 100644 --- a/libs/framework/src/service_registry.c +++ b/libs/framework/src/service_registry.c @@ -191,13 +191,19 @@ static celix_status_t serviceRegistry_registerServiceInternal(service_registry_p array_list_pt regs; long svcId = reservedId > 0 ? reservedId : celix_serviceRegistry_nextSvcId(registry); + celix_properties_setLong(dictionary, CELIX_FRAMEWORK_SERVICE_BUNDLE_ID, celix_bundle_getId(bundle)); + + if (svcType == CELIX_DEPRECATED_FACTORY_SERVICE) { + celix_properties_set(dictionary, CELIX_FRAMEWORK_SERVICE_SCOPE, CELIX_FRAMEWORK_SERVICE_SCOPE_BUNDLE); *registration = serviceRegistration_createServiceFactory(registry->callback, bundle, serviceName, svcId, serviceObject, dictionary); } else if (svcType == CELIX_FACTORY_SERVICE) { + celix_properties_set(dictionary, CELIX_FRAMEWORK_SERVICE_SCOPE, CELIX_FRAMEWORK_SERVICE_SCOPE_BUNDLE); *registration = celix_serviceRegistration_createServiceFactory(registry->callback, bundle, serviceName, svcId, (celix_service_factory_t*)serviceObject, dictionary); } else { //plain + celix_properties_set(dictionary, CELIX_FRAMEWORK_SERVICE_SCOPE, CELIX_FRAMEWORK_SERVICE_SCOPE_SINGLETON); *registration = serviceRegistration_create(registry->callback, bundle, serviceName, svcId, serviceObject, dictionary); } //printf("Registering service %li with name %s\n", svcId, serviceName);
