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 2021/07/30 14:34:44 UTC

[celix] 01/01: Adds support for the service.bundleid and service.scope framework props

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 <pe...@gmail.com>
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);