This is an automated email from the ASF dual-hosted git repository.

pnoltes pushed a commit to branch feature/87-refactor-use-services
in repository https://gitbox.apache.org/repos/asf/celix.git

commit 03c0a2ac78dee60fe487e056f1ab106942c27714
Author: Pepijn Noltes <pnol...@apache.org>
AuthorDate: Sat Mar 9 14:39:55 2024 +0100

    gh-87: Refactor ctx useService* impl to reuse service tracker.
    
    Note that also means that useService* functions and
    methods are no longer use-able in the Celix event thread.
---
 CHANGES.md                                         |   3 +
 bundles/shell/shell/gtest/CMakeLists.txt           |   6 +-
 bundles/shell/shell/gtest/src/ShellTestSuite.cc    |  54 +++++---
 bundles/shell/shell/src/help_command.c             |  40 +++---
 .../src/CelixBundleContextServicesTestSuite.cc     |  32 +----
 libs/framework/include/celix/BundleContext.h       |  12 +-
 libs/framework/include/celix_bundle_context.h      |  15 ++-
 libs/framework/src/bundle_context.c                | 148 ++++++---------------
 8 files changed, 139 insertions(+), 171 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 3221802a..7fee14e7 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -66,6 +66,9 @@ limitations under the License.
   The `celix_bundleContext_trackServicesWithOptions` is still available for 
more advanced use-cases.
 - Function `celix_bundle_destroyServiceTrackerList` is removed. The returned 
array list from 
   `celix_bundle_listServiceTrackers` is now configured to destroy the service 
trackers info entries.
+- It is no longer possible to use the `celix_bundleContext_useService*` 
functions or `celix::BundleContxt::useService*` 
+  methods on the Celix event thread. The calls will now immediately return and 
log an error if called on the
+  Celix event thread.
 
 ## New Features
 
diff --git a/bundles/shell/shell/gtest/CMakeLists.txt 
b/bundles/shell/shell/gtest/CMakeLists.txt
index 91a50aef..75d18ea8 100644
--- a/bundles/shell/shell/gtest/CMakeLists.txt
+++ b/bundles/shell/shell/gtest/CMakeLists.txt
@@ -19,8 +19,10 @@ add_executable(test_shell
         src/ShellTestSuite.cc
 )
 
+add_celix_bundle(celix_shell_empty_resource_test_bundle NO_ACTIVATOR VERSION 
0.0.0)
+
 target_link_libraries(test_shell PRIVATE Celix::framework Celix::shell_api 
GTest::gtest GTest::gtest_main)
-celix_target_bundle_set_definition(test_shell NAME TEST_BUNDLES Celix::shell)
+celix_target_bundle_set_definition(test_shell NAME TEST_BUNDLES Celix::shell 
celix_shell_empty_resource_test_bundle)
 target_compile_options(test_shell PRIVATE -Wno-deprecated-declarations)
 
 add_test(NAME test_shell COMMAND test_shell)
@@ -31,7 +33,7 @@ if (CELIX_CXX14)
     add_executable(test_cxx_shell src/ShellTestSuite.cc)
 
     target_link_libraries(test_cxx_shell PRIVATE Celix::framework 
Celix::shell_api GTest::gtest GTest::gtest_main)
-    celix_target_bundle_set_definition(test_cxx_shell NAME TEST_BUNDLES 
Celix::ShellCxx)
+    celix_target_bundle_set_definition(test_cxx_shell NAME TEST_BUNDLES 
Celix::ShellCxx celix_shell_empty_resource_test_bundle)
     target_compile_definitions(test_cxx_shell PRIVATE -DCXX_SHELL)
 
     add_test(NAME test_cxx_shell COMMAND test_cxx_shell)
diff --git a/bundles/shell/shell/gtest/src/ShellTestSuite.cc 
b/bundles/shell/shell/gtest/src/ShellTestSuite.cc
index 318a8379..b7b5f791 100644
--- a/bundles/shell/shell/gtest/src/ShellTestSuite.cc
+++ b/bundles/shell/shell/gtest/src/ShellTestSuite.cc
@@ -21,19 +21,20 @@
 #include <gtest/gtest.h>
 #include <thread>
 
-#include "celix_shell_command.h"
-#include "celix_framework_factory.h"
 #include "celix_bundle_context.h"
-#include "celix_shell.h"
-#include "celix_framework_utils.h"
 #include "celix_constants.h"
+#include "celix_framework_factory.h"
+#include "celix_framework_utils.h"
+#include "celix_shell.h"
+#include "celix_shell_command.h"
+#include "celix_stdlib_cleanup.h"
 
 class ShellTestSuite : public ::testing::Test {
 public:
     ShellTestSuite() : ctx{createFrameworkContext()} {
         auto* fw = celix_bundleContext_getFramework(ctx.get());
         size_t nr = celix_framework_utils_installBundleSet(fw, TEST_BUNDLES, 
true);
-        EXPECT_EQ(nr, 1); //shell bundle
+        EXPECT_EQ(nr, 2); //shell and  celix_shell_empty_resource_test_bundle 
bundle
     }
 
     static std::shared_ptr<celix_bundle_context_t> createFrameworkContext() {
@@ -54,12 +55,25 @@ public:
         }};
     }
 
+    long getBundleIdForResourceBundle() const {
+        celix_autoptr(celix_array_list_t) bundles = 
celix_bundleContext_listBundles(ctx.get());
+        for (auto i = 0 ; i < celix_arrayList_size(bundles); ++i) {
+            auto bndId = celix_arrayList_getLong(bundles, i);
+            celix_autofree char* name = 
celix_bundleContext_getBundleSymbolicName(ctx.get(), bndId);
+            if (strstr(name, "resource") != nullptr) {
+                return bndId;
+            }
+
+        }
+        return -1;
+    }
+
     std::shared_ptr<celix_bundle_context_t> ctx;
 };
 
 TEST_F(ShellTestSuite, shellBundleInstalledTest) {
     auto *bndIds = celix_bundleContext_listBundles(ctx.get());
-    EXPECT_EQ(1, celix_arrayList_size(bndIds));
+    EXPECT_EQ(2, celix_arrayList_size(bndIds));
     celix_arrayList_destroy(bndIds);
 }
 
@@ -71,8 +85,6 @@ static void 
callCommand(std::shared_ptr<celix_bundle_context_t>& ctx, const char
         celix_bundle_context_t* context{};
         long tracker{-1};
     };
-    // Note that using celix_bundleContext_useServiceWithOptions to call 
command quit/stop may result in deadlock.
-    // For more on this, see https://github.com/apache/celix/issues/629
     struct callback_data data{};
     data.cmdLine = cmdLine;
     data.cmdShouldSucceed = cmdShouldSucceed;
@@ -104,9 +116,10 @@ TEST_F(ShellTestSuite, testAllCommandsAreCallable) {
     callCommand(ctx, "non-existing", false);
     callCommand(ctx, "install a-bundle-loc.zip", true);
     callCommand(ctx, "help", true);
-    callCommand(ctx, "help lb", false); //note need namespace
+    callCommand(ctx, "help lb", true);
     callCommand(ctx, "help celix::lb", true);
     callCommand(ctx, "help non-existing-command", false);
+    callCommand(ctx, "help celix::non-existing-command-with-namespace", false);
     callCommand(ctx, "lb", true);
     callCommand(ctx, "lb -l", true);
     callCommand(ctx, "query", true);
@@ -144,7 +157,8 @@ TEST_F(ShellTestSuite, stopFrameworkTest) {
 
 TEST_F(ShellTestSuite, stopSelfTest) {
     auto* list = celix_bundleContext_listBundles(ctx.get());
-    EXPECT_EQ(1, celix_arrayList_size(list));
+    ASSERT_GE(celix_arrayList_size(list), 1);
+    auto nrOfBundles = celix_arrayList_size(list);
     long shellBundleId = celix_arrayList_getLong(list, 0);
     celix_arrayList_destroy(list);
 
@@ -156,24 +170,33 @@ TEST_F(ShellTestSuite, stopSelfTest) {
     std::this_thread::sleep_for(std::chrono::milliseconds{100});
 
     list = celix_bundleContext_listBundles(ctx.get());
-    EXPECT_EQ(0, celix_arrayList_size(list));
+    EXPECT_EQ(nrOfBundles-1, celix_arrayList_size(list));
     celix_arrayList_destroy(list);
 }
 
 TEST_F(ShellTestSuite, queryTest) {
+    struct data {
+        long resourceBundleId;
+    };
+    data data{};
+    data.resourceBundleId = getBundleIdForResourceBundle();
+
     celix_service_use_options_t opts{};
     opts.filter.serviceName = CELIX_SHELL_COMMAND_SERVICE_NAME;
     opts.filter.filter = "(command.name=celix::query)";
     opts.waitTimeoutInSeconds = 1.0;
-    opts.use = [](void */*handle*/, void *svc) {
+    opts.callbackHandle = (void*)&data;
+    opts.use = [](void* handle, void *svc) {
+        auto *d = static_cast<struct data*>(handle);
         auto *command = static_cast<celix_shell_command_t*>(svc);
-        EXPECT_TRUE(command != nullptr);
+        ASSERT_TRUE(command != nullptr);
+        ASSERT_TRUE(d != nullptr);
 
         {
             char *buf = nullptr;
             size_t len;
             FILE *sout = open_memstream(&buf, &len);
-            command->executeCommand(command->handle, (char *) "query", sout, 
sout);
+            command->executeCommand(command->handle, "query", sout, sout);
             fclose(sout);
             char* found = strstr(buf, "Provided services found 1"); //note 
could be 11, 12, etc
             EXPECT_TRUE(found != nullptr);
@@ -183,7 +206,8 @@ TEST_F(ShellTestSuite, queryTest) {
             char *buf = nullptr;
             size_t len;
             FILE *sout = open_memstream(&buf, &len);
-            command->executeCommand(command->handle, (char *) "query 0", sout, 
sout); //note query framework bundle -> no results
+            auto cmd = std::string{"query "} + 
std::to_string(d->resourceBundleId);
+            command->executeCommand(command->handle, cmd.c_str(), sout, sout); 
//note query test resource bundle -> no results
             fclose(sout);
             char* found = strstr(buf, "No results"); //note could be 11, 12, 
etc
             EXPECT_TRUE(found != nullptr);
diff --git a/bundles/shell/shell/src/help_command.c 
b/bundles/shell/shell/src/help_command.c
index 092a32f4..746de5c0 100644
--- a/bundles/shell/shell/src/help_command.c
+++ b/bundles/shell/shell/src/help_command.c
@@ -22,8 +22,9 @@
 #include <stdint.h>
 
 #include "celix_array_list.h"
-#include "celix_utils.h"
 #include "celix_shell.h"
+#include "celix_stdlib_cleanup.h"
+#include "celix_utils.h"
 #include "std_commands.h"
 
 struct print_handle {
@@ -51,11 +52,9 @@ static void printHelp(void *handle, void *svc) {
     sub = strtok_r(NULL, CELIX_SHELL_COMMAND_SEPARATOR, &save_ptr);
 
     if (sub == NULL) {
-        unsigned int i;
         celix_array_list_t *commands = NULL;
-
         shell->getCommands(shell->handle, &commands);
-        for (i = 0; i < celix_arrayList_size(commands); i++) {
+        for (int i = 0; i < celix_arrayList_size(commands); i++) {
             char *name = celix_arrayList_get(commands, i);
             fprintf(out, "%s\n", name);
             free(name);
@@ -71,17 +70,19 @@ static void printHelp(void *handle, void *svc) {
         shell->getCommands(shell->handle, &commands);
         bool cmdFound = false;
         for (i = 0; i < celix_arrayList_size(commands); i++) {
-            char *name = celix_arrayList_get(commands, i);
-            if (strcmp(sub, name) == 0) {
+            char *fqn = celix_arrayList_get(commands, i);
+            bool hasNamespace = strstr(fqn, "::") != NULL;
+            char* localName = hasNamespace ? strstr(fqn, "::") + 2 : fqn;
+            if (strcmp(sub, fqn) == 0 || (hasNamespace && strcmp(sub, 
localName) == 0)) {
                 cmdFound = true;
                 char *usage_str = NULL;
                 char *desc_str = NULL;
 
-                sub_status_desc = shell->getCommandDescription(shell->handle, 
name, &desc_str);
-                sub_status_usage = shell->getCommandUsage(shell->handle, name, 
&usage_str);
+                sub_status_desc = shell->getCommandDescription(shell->handle, 
fqn, &desc_str);
+                sub_status_usage = shell->getCommandUsage(shell->handle, fqn, 
&usage_str);
 
                 if (sub_status_usage == CELIX_SUCCESS && sub_status_desc == 
CELIX_SUCCESS) {
-                    fprintf(out, "Command     : %s\n", name);
+                    fprintf(out, "Command     : %s\n", fqn);
                     fprintf(out, "Usage       : %s\n", usage_str == NULL ? "" 
: usage_str);
                     fprintf(out, "Description : %s\n", desc_str == NULL ? "" : 
desc_str);
                 } else {
@@ -91,7 +92,7 @@ static void printHelp(void *handle, void *svc) {
                 free(usage_str);
                 free(desc_str);
             }
-            free(name);
+            free(fqn);
         }
         celix_arrayList_destroy(commands);
 
@@ -103,16 +104,23 @@ static void printHelp(void *handle, void *svc) {
     }
 }
 
-bool helpCommand_execute(void *handle, const char *const_cmdLine, FILE *out, 
FILE *err) {
-       celix_bundle_context_t *ctx = handle;
-       struct print_handle printHandle;
-       char *cmdLine = celix_utils_strdup(const_cmdLine);
+bool helpCommand_execute(void* handle, const char* const_cmdLine, FILE* out, 
FILE* err) {
+    celix_bundle_context_t* ctx = handle;
+    celix_autofree char* cmdLine = celix_utils_strdup(const_cmdLine);
+
+    long trkId = celix_bundleContext_trackServices(ctx, 
CELIX_SHELL_SERVICE_NAME);
+    if (trkId < 0) {
+        fprintf(err, "Error tracking shell services\n");
+        return false;
+    }
 
+    struct print_handle printHandle;
     printHandle.cmdLine = cmdLine;
     printHandle.out = out;
     printHandle.err = err;
-       bool called = celix_bundleContext_useService(ctx, 
CELIX_SHELL_SERVICE_NAME, &printHandle, printHelp);
+    bool called = celix_bundleContext_useTrackedService(ctx, trkId, 
&printHandle, printHelp);
+
+    celix_bundleContext_stopTracker(ctx, trkId);
 
-       free(cmdLine);
     return called & printHandle.callSucceeded;
 }
diff --git a/libs/framework/gtest/src/CelixBundleContextServicesTestSuite.cc 
b/libs/framework/gtest/src/CelixBundleContextServicesTestSuite.cc
index 12ffcd94..a164520f 100644
--- a/libs/framework/gtest/src/CelixBundleContextServicesTestSuite.cc
+++ b/libs/framework/gtest/src/CelixBundleContextServicesTestSuite.cc
@@ -974,16 +974,14 @@ TEST_F(CelixBundleContextServicesTestSuite, 
ServiceTrackerWithRaceConditionTest)
     celix_bundleContext_stopTracker(ctx, trackerId);
 };
 
-TEST_F(CelixBundleContextServicesTestSuite, UseServiceDoesNotBlockInEventLoop) 
{
-    void *svc1 = (void*)0x100;
-
-    auto set = [](void *handle, void */*svc*/) {
-        celix_bundle_context_t *ctx = static_cast<celix_bundle_context_t 
*>(handle);
+TEST_F(CelixBundleContextServicesTestSuite, UseServiceDoesNotWorkInEventLoop) {
+    auto callback = [](void* data) {
+        auto* ctx = static_cast<celix_bundle_context_t*>(data);
         celix_service_use_options_t use_opts{};
         use_opts.filter.serviceName = "NotAvailable";
         use_opts.waitTimeoutInSeconds = 3600; // unacceptable long blocking
         use_opts.callbackHandle = nullptr;
-        use_opts.use =  [](void *handle, void *svc) {
+        use_opts.use = [](void* handle, void* svc) {
             FAIL() << "We shouldn't get here: (" << handle << "," << svc << 
")";
         };
 
@@ -991,25 +989,9 @@ TEST_F(CelixBundleContextServicesTestSuite, 
UseServiceDoesNotBlockInEventLoop) {
         ASSERT_FALSE(called);
     };
 
-    long svcId1 = celix_bundleContext_registerService(ctx, svc1, "NA", 
nullptr);
-    ASSERT_GE(svcId1, 0);
-
-    celix_service_tracking_options_t opts{};
-    opts.callbackHandle = (void*)ctx;
-    opts.filter.serviceName = "NA";
-    opts.set = set;
-    long trackerId = celix_bundleContext_trackServicesWithOptionsAsync(ctx, 
&opts);
-    ASSERT_TRUE(trackerId >= 0);
-
-    void *svc2 = (void*)0x200; //no ranking
-    long svcId2 = celix_bundleContext_registerServiceAsync(ctx, svc2, 
"NotAvailable", nullptr);
-    ASSERT_GE(svcId2, 0);
-    celix_bundleContext_waitForAsyncTracker(ctx, trackerId);
-    celix_bundleContext_waitForAsyncRegistration(ctx, svcId2);
-
-    celix_bundleContext_unregisterService(ctx, svcId2);
-    celix_bundleContext_stopTracker(ctx, trackerId);
-    celix_bundleContext_unregisterService(ctx, svcId1);
+    long eventId = celix_framework_fireGenericEvent(
+        fw, 0, CELIX_FRAMEWORK_BUNDLE_ID, "test event", ctx, callback, 
nullptr, nullptr);
+    celix_framework_waitForGenericEvent(fw, eventId);
 }
 
 TEST_F(CelixBundleContextServicesTestSuite, ServicesTrackerSetTest) {
diff --git a/libs/framework/include/celix/BundleContext.h 
b/libs/framework/include/celix/BundleContext.h
index d98c0c5e..1bb89fae 100644
--- a/libs/framework/include/celix/BundleContext.h
+++ b/libs/framework/include/celix/BundleContext.h
@@ -33,7 +33,7 @@
 #include "celix/Bundle.h"
 #include "celix/Framework.h"
 
-#include "celix/dm/DependencyManager.h" //TODO, TBD include or forward 
declaration?
+#include "celix/dm/DependencyManager.h"
 
 namespace celix {
 
@@ -106,6 +106,10 @@ namespace celix {
         /**
          * @brief Use a service registered in the Celix framework using a 
fluent builder API.
          *
+         * @deprecated celix_bundleContext_useService are deprecated and 
should be considered test utils functions. In
+         * operational code use celix_bundleContext_trackService* combined 
with celix_bundleContext_useTrackedService*
+         * functions instead.
+         *
          * The service use can be fine tuned using the returned 
UseServiceBuilder API.
          *
          * With this API a Celix service can be used by providing use 
functions.
@@ -130,6 +134,7 @@ namespace celix {
          * @return A UseServiceBuilder object.
          */
         template<typename I>
+        [[deprecated]]
         UseServiceBuilder<I> useService(const std::string& name = {}) {
             return UseServiceBuilder<I>{cCtx, celix::typeName<I>(name), true};
         }
@@ -137,6 +142,10 @@ namespace celix {
         /**
          * @brief Use services registered in the Celix framework using a 
fluent builder API.
          *
+         * @deprecated celix_bundleContext_useService are deprecated and 
should be considered test utils functions. In
+         * operational code use celix_bundleContext_trackService* combined 
with celix_bundleContext_useTrackedService*
+         * functions instead.
+         *
          * The service use can be fine tuned using the returned 
UseServiceBuilder API.
          *
          * With this API Celix services can be used by providing use functions.
@@ -158,6 +167,7 @@ namespace celix {
          * @return A UseServiceBuilder object.
          */
         template<typename I>
+        [[deprecated]]
         UseServiceBuilder<I> useServices(const std::string& name = {}) {
             return UseServiceBuilder<I>{cCtx, celix::typeName<I>(name), false};
         }
diff --git a/libs/framework/include/celix_bundle_context.h 
b/libs/framework/include/celix_bundle_context.h
index fb9dc94b..56ec0e5c 100644
--- a/libs/framework/include/celix_bundle_context.h
+++ b/libs/framework/include/celix_bundle_context.h
@@ -391,7 +391,8 @@ CELIX_FRAMEWORK_EXPORT celix_array_list_t* 
celix_bundleContext_findServicesWithO
  * @brief Use the service with the provided service id using the provided 
callback. The Celix framework will ensure that
  * the targeted service cannot be removed during the callback.
  *
- * @deprecated Use celix_bundleContext_trackService* combined with 
celix_bundleContext_useTrackedService* functions
+ * @deprecated celix_bundleContext_useService are deprecated and should be 
considered test utils functions. In
+ * operational code use celix_bundleContext_trackService* combined with 
celix_bundleContext_useTrackedService* functions
  * instead.
  *
  * The svc is should only be considered valid during the callback.
@@ -417,7 +418,8 @@ CELIX_FRAMEWORK_DEPRECATED_EXPORT bool 
celix_bundleContext_useServiceWithId(celi
 /**
  * @brief Use the highest ranking service with the provided service name using 
the provided callback.
  *
- * @deprecated Use celix_bundleContext_trackService* combined with 
celix_bundleContext_useTrackedService* functions
+ * @deprecated celix_bundleContext_useService are deprecated and should be 
considered test utils functions. In
+ * operational code use celix_bundleContext_trackService* combined with 
celix_bundleContext_useTrackedService* functions
  * instead.
  *
  * The Celix framework will ensure that the targeted service cannot be removed 
during the callback.
@@ -444,7 +446,8 @@ CELIX_FRAMEWORK_DEPRECATED_EXPORT bool 
celix_bundleContext_useService(
 /**
  * @brief Use the services with the provided service name using the provided 
callback.
  *
- * @deprecated Use celix_bundleContext_trackService* combined with 
celix_bundleContext_useTrackedService* functions
+ * @deprecated celix_bundleContext_useService are deprecated and should be 
considered test utils functions. In
+ * operational code use celix_bundleContext_trackService* combined with 
celix_bundleContext_useTrackedService* functions
  * instead.
  *
  * The Celix framework will ensure that the targeted service cannot be removed 
during the callback.
@@ -548,7 +551,8 @@ typedef struct celix_service_use_options {
 /**
  * @brief Use the highest ranking service satisfying the provided service 
filter options using the provided callback.
  *
- * @deprecated Use celix_bundleContext_trackService* combined with 
celix_bundleContext_useTrackedService* functions
+ * @deprecated celix_bundleContext_useService are deprecated and should be 
considered test utils functions. In
+ * operational code use celix_bundleContext_trackService* combined with 
celix_bundleContext_useTrackedService* functions
  * instead.
  *
  * The Celix framework will ensure that the targeted service cannot be removed 
during the callback.
@@ -572,7 +576,8 @@ CELIX_FRAMEWORK_DEPRECATED_EXPORT bool 
celix_bundleContext_useServiceWithOptions
 /**
  * @brief Use the services with the provided service filter options using the 
provided callback.
  *
- * @deprecated Use celix_bundleContext_trackService* combined with 
celix_bundleContext_useTrackedService* functions
+ * @deprecated celix_bundleContext_useService are deprecated and should be 
considered test utils functions. In
+ * operational code use celix_bundleContext_trackService* combined with 
celix_bundleContext_useTrackedService* functions
  * instead.
  *
  * The Celix framework will ensure that the targeted service cannot be removed 
during the callback.
diff --git a/libs/framework/src/bundle_context.c 
b/libs/framework/src/bundle_context.c
index 99624cae..149fe611 100644
--- a/libs/framework/src/bundle_context.c
+++ b/libs/framework/src/bundle_context.c
@@ -1118,130 +1118,64 @@ size_t celix_bundleContext_useServices(
     return celix_bundleContext_useServicesWithOptions(ctx, &opts);
 }
 
-typedef struct celix_bundle_context_use_service_data {
-    celix_bundle_context_t* ctx;
-    const celix_service_use_options_t* opts;
-
-    bool called; //for use service
-    size_t count; //for use services
-    celix_service_tracker_t * svcTracker;
-} celix_bundle_context_use_service_data_t;
-
-static void 
celix_bundleContext_useServiceWithOptions_1_CreateServiceTracker(void *data) {
-    celix_bundle_context_use_service_data_t* d = data;
-    assert(celix_framework_isCurrentThreadTheEventLoop(d->ctx->framework));
-
-    celix_service_tracking_options_t trkOpts = 
CELIX_EMPTY_SERVICE_TRACKING_OPTIONS;
-    trkOpts.filter = d->opts->filter;
-
-    d->called = false;
-    d->count = 0;
-    d->svcTracker = celix_serviceTracker_createWithOptions(d->ctx, &trkOpts);
-}
-
-static void celix_bundleContext_useServiceWithOptions_2_UseServiceTracker(void 
*data) {
-    celix_bundle_context_use_service_data_t* d = data;
-    assert(celix_framework_isCurrentThreadTheEventLoop(d->ctx->framework));
-
-    d->called = celix_serviceTracker_useHighestRankingService(d->svcTracker, 
d->opts->filter.serviceName, 0, d->opts->callbackHandle, d->opts->use, 
d->opts->useWithProperties, d->opts->useWithOwner);
-}
-
-bool celix_bundleContext_useServiceWithOptions(
-        celix_bundle_context_t *ctx,
-        const celix_service_use_options_t *opts) {
+static size_t celix_bundleContext_useServicesInternal(celix_bundle_context_t 
*ctx,
+                                                      const 
celix_service_use_options_t *opts, bool singular) {
     if (opts == NULL || opts->filter.serviceName == NULL) {
-        return false;
+        return 0;
     }
 
-    celix_bundle_context_use_service_data_t data = {0};
-    data.ctx = ctx;
-    data.opts = opts;
-    bool called = false;
-
     if (celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) {
-        // Ignore timeout: blocking the event loop prevents any progress to be 
made
-        
celix_bundleContext_useServiceWithOptions_1_CreateServiceTracker(&data);
-        celix_bundleContext_useServiceWithOptions_2_UseServiceTracker(&data);
-        celix_serviceTracker_destroy(data.svcTracker);
-        return data.called;
+        fw_log(ctx->framework->logger,
+               CELIX_LOG_LEVEL_ERROR,
+               "Cannot use services on the event loop thread. Ignoring call.");
+        return 0;
     }
 
-    long eventId = celix_framework_fireGenericEvent(ctx->framework, -1, 
celix_bundle_getId(ctx->bundle), "create service tracker for 
celix_bundleContext_useServiceWithOptions", &data, 
celix_bundleContext_useServiceWithOptions_1_CreateServiceTracker, NULL, NULL);
-    celix_framework_waitForGenericEvent(ctx->framework, eventId);
-
+    celix_service_tracking_options_t trackingOpts = 
CELIX_EMPTY_SERVICE_TRACKING_OPTIONS;
+    memcpy(&trackingOpts.filter, &opts->filter, sizeof(opts->filter));
+    long trkId = celix_bundleContext_trackServicesWithOptions(ctx, 
&trackingOpts);
+    if (trkId < 0) {
+        return 0;
+    }
 
-    if(opts->flags & CELIX_SERVICE_USE_DIRECT) {
-        if(opts->flags & CELIX_SERVICE_USE_SOD) {
-            // check 
CelixBundleContextServicesTestSuite.UseServiceOnDemandDirectlyWithAsyncRegisterTest
 to see what is "service on demand".
-            celix_framework_waitUntilNoPendingRegistration(ctx->framework);
+    //Note because useService* is primary an API used in tests, waiting for 
events to that service-on-demand is
+    //working and useService* calls work after an async service 
(un)registration.
+    celix_framework_waitForEmptyEventQueue(ctx->framework);
+
+    celix_tracked_service_use_options_t useOpts = 
CELIX_EMPTY_TRACKER_SERVICE_USE_OPTIONS;
+    useOpts.callbackHandle = opts->callbackHandle;
+    useOpts.use = opts->use;
+    useOpts.useWithProperties = opts->useWithProperties;
+    useOpts.useWithOwner = opts->useWithOwner;
+
+    size_t count;
+    if (singular) {
+        struct timespec start = celix_gettime(CLOCK_MONOTONIC);
+        bool called = celix_bundleContext_useTrackedServiceWithOptions(ctx, 
trkId, &useOpts);
+        if (!called && opts->waitTimeoutInSeconds > 0) {
+            while (!called && celix_elapsedtime(CLOCK_MONOTONIC, start) < 
opts->waitTimeoutInSeconds) {
+                usleep(1000);
+                called = celix_bundleContext_useTrackedServiceWithOptions(ctx, 
trkId, &useOpts);
+            }
         }
-        called = 
celix_serviceTracker_useHighestRankingService(data.svcTracker, NULL, 
opts->waitTimeoutInSeconds, opts->callbackHandle, opts->use, 
opts->useWithProperties, opts->useWithOwner);
+        count = called ? 1 : 0;
     } else {
-        struct timespec startTime = celix_gettime(CLOCK_MONOTONIC);
-        bool useServiceIsDone = false;
-        do {
-            eventId = celix_framework_fireGenericEvent(ctx->framework, -1, 
celix_bundle_getId(ctx->bundle), "use service tracker for 
celix_bundleContext_useServiceWithOptions", &data, 
celix_bundleContext_useServiceWithOptions_2_UseServiceTracker, NULL, NULL);
-            celix_framework_waitForGenericEvent(ctx->framework, eventId);
-
-            bool timeoutNotUsed = opts->waitTimeoutInSeconds == 0;
-            bool timeoutExpired = celix_elapsedtime(CLOCK_MONOTONIC, 
startTime) > opts->waitTimeoutInSeconds;
-
-            called = data.called;
-
-            useServiceIsDone = timeoutNotUsed || timeoutExpired || called;
-            if (!useServiceIsDone) {
-                usleep(10);
-            }
-        } while (!useServiceIsDone);
+        count = celix_bundleContext_useTrackedServicesWithOptions(ctx, trkId, 
&useOpts);
     }
-
-    eventId = celix_framework_fireGenericEvent(ctx->framework, -1, 
celix_bundle_getId(ctx->bundle), "close service tracker for 
celix_bundleContext_useServiceWithOptions", data.svcTracker, (void 
*)celix_serviceTracker_destroy, NULL, NULL);
-    celix_framework_waitForGenericEvent(ctx->framework, eventId);
-
-    return called;
+    celix_bundleContext_stopTracker(ctx, trkId);
+    return count;
 }
 
-static void 
celix_bundleContext_useServicesWithOptions_2_UseServiceTracker(void *data) {
-    celix_bundle_context_use_service_data_t* d = data;
-    d->count = celix_serviceTracker_useServices(d->svcTracker, 
d->opts->filter.serviceName, d->opts->callbackHandle, d->opts->use, 
d->opts->useWithProperties, d->opts->useWithOwner);
+bool celix_bundleContext_useServiceWithOptions(
+        celix_bundle_context_t *ctx,
+        const celix_service_use_options_t *opts) {
+    return celix_bundleContext_useServicesInternal(ctx, opts, true) > 0;
 }
 
 size_t celix_bundleContext_useServicesWithOptions(
         celix_bundle_context_t *ctx,
         const celix_service_use_options_t *opts) {
-    if (opts == NULL || opts->filter.serviceName == NULL) {
-        return 0;
-    }
-
-    celix_bundle_context_use_service_data_t data = {0};
-    data.ctx = ctx;
-    data.opts = opts;
-
-    if (celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) {
-        
celix_bundleContext_useServiceWithOptions_1_CreateServiceTracker(&data);
-        celix_bundleContext_useServicesWithOptions_2_UseServiceTracker(&data);
-        celix_serviceTracker_destroy(data.svcTracker);
-        return data.count;
-    }
-
-    long eventId = celix_framework_fireGenericEvent(ctx->framework, -1, 
celix_bundle_getId(ctx->bundle), "create service tracker for 
celix_bundleContext_useServicesWithOptions", &data, 
celix_bundleContext_useServiceWithOptions_1_CreateServiceTracker, NULL, NULL);
-    celix_framework_waitForGenericEvent(ctx->framework, eventId);
-
-    if (opts->flags & CELIX_SERVICE_USE_DIRECT) {
-        if(opts->flags & CELIX_SERVICE_USE_SOD) {
-            // check 
CelixBundleContextServicesTestSuite.UseServicesOnDemandDirectlyWithAsyncRegisterTest
 to see what is "service on demand".
-            celix_framework_waitUntilNoPendingRegistration(ctx->framework);
-        }
-        celix_bundleContext_useServicesWithOptions_2_UseServiceTracker(&data);
-    } else {
-        eventId = celix_framework_fireGenericEvent(ctx->framework, -1, 
celix_bundle_getId(ctx->bundle), "use service tracker for 
celix_bundleContext_useServicesWithOptions", &data, 
celix_bundleContext_useServicesWithOptions_2_UseServiceTracker, NULL, NULL);
-        celix_framework_waitForGenericEvent(ctx->framework, eventId);
-    }
-
-    eventId = celix_framework_fireGenericEvent(ctx->framework, -1, 
celix_bundle_getId(ctx->bundle), "use service tracker for 
celix_bundleContext_useServicesWithOptions", data.svcTracker, (void 
*)celix_serviceTracker_destroy, NULL, NULL);
-    celix_framework_waitForGenericEvent(ctx->framework, eventId);
-
-    return data.count;
+    return celix_bundleContext_useServicesInternal(ctx, opts, false);
 }
 
 long celix_bundleContext_trackServices(bundle_context_t* ctx, const char* 
serviceName) {

Reply via email to