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

pnoltes pushed a commit to branch feature/585-celix-conditions
in repository https://gitbox.apache.org/repos/asf/celix.git

commit 1af0812458d2f06fccafe85197e1420a82f8d6e6
Author: Pepijn Noltes <[email protected]>
AuthorDate: Tue Jun 27 20:05:50 2023 +0200

    Add initial setup for OSGi-like conditions
---
 documents/conditions.md                         |  23 +++++
 libs/framework/CMakeLists.txt                   |   1 +
 libs/framework/include/celix_condition.h        |  92 ++++++++++++++++++++
 libs/framework/src/celix_framework_conditions.c | 107 +++++++++++++++++++++++
 libs/framework/src/celix_framework_conditions.h |  73 ++++++++++++++++
 libs/framework/src/framework.c                  | 108 +++++++++++++++---------
 libs/framework/src/framework_private.h          |   6 ++
 7 files changed, 371 insertions(+), 39 deletions(-)

diff --git a/documents/conditions.md b/documents/conditions.md
new file mode 100644
index 00000000..b2c170ee
--- /dev/null
+++ b/documents/conditions.md
@@ -0,0 +1,23 @@
+---
+title: Apache Celix Conditions
+---
+
+<!--
+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.
+-->
+
+# Apache Celix Conditions
+TODO
\ No newline at end of file
diff --git a/libs/framework/CMakeLists.txt b/libs/framework/CMakeLists.txt
index 82968846..a0c71fc8 100644
--- a/libs/framework/CMakeLists.txt
+++ b/libs/framework/CMakeLists.txt
@@ -34,6 +34,7 @@ set(FRAMEWORK_SRC
         src/framework_bundle_lifecycle_handler.c
         src/celix_bundle_state.c
         src/celix_framework_utils.c
+        src/celix_framework_conditions.c
         src/celix_module_private.h)
 set(FRAMEWORK_DEPS libuuid::libuuid CURL::libcurl ZLIB::ZLIB ${CMAKE_DL_LIBS})
 
diff --git a/libs/framework/include/celix_condition.h 
b/libs/framework/include/celix_condition.h
new file mode 100644
index 00000000..55fe37a1
--- /dev/null
+++ b/libs/framework/include/celix_condition.h
@@ -0,0 +1,92 @@
+/*
+ * 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_CONDITION_H_
+#define CELIX_CONDITION_H_
+
+#include "celix_framework_export.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*!
+ * @brief The name of the condition service.
+ */
+#define CELIX_CONDITION_SERVICE_NAME "celix_condition"
+
+/*!
+ * @brief The version of the condition service.
+ */
+#define CELIX_CONDITION_SERVICE_VERSION "1.0.0"
+
+/*!
+ * @brief The property key used to specify the condition id.
+ * A condition id can only identify a single condition.
+ */
+#define CELIX_CONDITION_ID "celix.condition.id"
+
+/*!
+ * @brief The unique identifier for the default True condition.
+ * The default True condition is registered by the framework during framework 
initialization and therefore
+ * can always be relied upon.
+ */
+#define CELIX_CONDITION_ID_TRUE "true"
+
+/*!
+ * @brief The unique identifier for the framework ready condition.
+ * The framework ready condition is registered by the framework after all 
install configured bundles are installed,
+ * all start configured bundles are started and after the Apache Celix Event 
Queue becomes empty.
+ *
+ * Note that after the framework ready condition is registered, the event 
queue can become non-empty again.
+ * For example if a component depends on the "framework.ready" condition.
+ */
+#define CELIX_CONDITION_ID_FRAMEWORK_READY "framework.ready"
+
+/**
+ * @brief Celix condition service struct.
+ *
+ * In dynamic systems, such as OSGi and Apache Celix, one of the more 
challenging problems can be to define when
+ * a system or part of it is ready to do work. The answer can change depending 
on the individual perspective.
+ * The developer of a web server might say, the system is ready when the 
server starts listening on port 80.
+ * An application developer however would define the system as ready when the 
database connection is up and all
+ * servlets are registered. Taking the application developers view, the web 
server should start listening on
+ * port 80 when the application is ready and not beforehand.
+ *
+ * The Condition service interface is a marker interface designed to address 
this issue.
+ * Its role is to provide a dependency that can be tracked. It acts as a 
defined signal to other services.
+ *
+ * A Condition service must be registered with the "celix.condition.id" 
service property.
+ */
+typedef struct celix_condition {
+    void* handle; /**< private dummy handle, note not used in marker service 
struct, but added to ensure
+                     sizeof(celix_condition_t) != 0  */
+} celix_condition_t;
+
+/**
+ * @brief A condition service struct instance that can be used to register 
celix_condition services.
+ * This can be helpful to avoid a bundle having to implement this service to 
register a celix_condition service.
+ */
+CELIX_FRAMEWORK_EXPORT celix_condition_t CELIX_CONDITION_INSTANCE;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CELIX_CONDITION_H_ */
diff --git a/libs/framework/src/celix_framework_conditions.c 
b/libs/framework/src/celix_framework_conditions.c
new file mode 100644
index 00000000..3105baf3
--- /dev/null
+++ b/libs/framework/src/celix_framework_conditions.c
@@ -0,0 +1,107 @@
+/*
+* 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 "framework_private.h"
+#include "celix_condition.h"
+#include "celix_constants.h"
+
+void celix_frameworkConditions_registerInitialConditions(celix_framework_t* 
framework) {
+    long svcId = -1L;
+    celix_bundle_context_t* ctx = 
celix_framework_getFrameworkContext(framework);
+    celixThreadMutex_lock(&framework->conditions.mutex);
+    celix_service_registration_options_t opts = 
CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS;
+    opts.serviceName = CELIX_CONDITION_SERVICE_NAME;
+    opts.serviceVersion = CELIX_CONDITION_SERVICE_VERSION;
+    opts.svc = &CELIX_CONDITION_INSTANCE;
+    opts.properties = celix_properties_create();
+    if (opts.properties) {
+        celix_properties_set(opts.properties, CELIX_CONDITION_ID, 
CELIX_CONDITION_ID_FRAMEWORK_READY);
+        svcId = celix_bundleContext_registerServiceWithOptionsAsync(ctx, 
&opts);
+    }
+    celix_status_t addStatus = 
celix_arrayList_add(framework->conditions.initialConditionSvcIds, (void*)svcId);
+    if (addStatus != CELIX_SUCCESS) {
+        celix_bundleContext_unregisterService(ctx, svcId);
+        fw_log(framework->logger, CELIX_LOG_LEVEL_ERROR, "Error adding initial 
condition service id to list");
+    }
+    celixThreadMutex_unlock(&framework->conditions.mutex);
+}
+
+void celix_frameworkConditions_unregisterInitialConditions(celix_framework_t* 
framework) {
+    celix_bundle_context_t* ctx = 
celix_framework_getFrameworkContext(framework);
+    celixThreadMutex_lock(&framework->conditions.mutex);
+    for (int i = 0; i < 
celix_arrayList_size(framework->conditions.initialConditionSvcIds); ++i) {
+        long svcId = 
(long)celix_arrayList_get(framework->conditions.initialConditionSvcIds, i);
+        celix_bundleContext_unregisterServiceAsync(ctx, svcId, NULL, NULL);
+    }
+    celix_arrayList_clear(framework->conditions.initialConditionSvcIds);
+    celixThreadMutex_unlock(&framework->conditions.mutex);
+}
+
+static void celix_frameworkConditions_checkFrameworkReady(void* data) {
+    celix_framework_t* framework = data;
+    celix_bundle_context_t* ctx = 
celix_framework_getFrameworkContext(framework);
+
+    celixThreadMutex_lock(&framework->dispatcher.mutex);
+    bool isEventQueueEmpty = framework->dispatcher.eventQueueSize == 0 && 
celix_arrayList_size(framework->dispatcher.dynamicEventQueue) == 0;
+    bool isActive = framework->dispatcher.active;
+    celixThreadMutex_unlock(&framework->dispatcher.mutex);
+
+    if (!isActive) {
+        fw_log(framework->logger, CELIX_LOG_LEVEL_DEBUG, "Framework is not 
active anymore, so no need to register the framework ready condition");
+        return;
+    }
+
+    if (isEventQueueEmpty) {
+        celixThreadMutex_lock(&framework->conditions.mutex);
+        celix_service_registration_options_t opts = 
CELIX_EMPTY_SERVICE_REGISTRATION_OPTIONS;
+        opts.serviceName = CELIX_CONDITION_SERVICE_NAME;
+        opts.serviceVersion = CELIX_CONDITION_SERVICE_VERSION;
+        opts.svc = &CELIX_CONDITION_INSTANCE;
+        opts.properties = celix_properties_create();
+        if (opts.properties) {
+            celix_properties_set(opts.properties, CELIX_CONDITION_ID, 
CELIX_CONDITION_ID_FRAMEWORK_READY);
+            long svcId = 
celix_bundleContext_registerServiceWithOptionsAsync(ctx, &opts);
+            celix_status_t addStatus = 
celix_arrayList_add(framework->conditions.frameworkReadyConditionSvcIds, 
(void*)svcId);
+            if (addStatus != CELIX_SUCCESS) {
+                celix_bundleContext_unregisterService(ctx, svcId);
+                fw_log(framework->logger, CELIX_LOG_LEVEL_ERROR, "Error adding 
framework ready condition service id to list");
+            }
+        }
+        celixThreadMutex_unlock(&framework->conditions.mutex);
+    } else {
+        //try again later on the event queue
+        celix_framework_fireGenericEvent(framework, -1, 
CELIX_FRAMEWORK_BUNDLE_ID, "Check event queue for framework ready condition 
service", framework, celix_frameworkConditions_checkFrameworkReady, NULL, NULL);
+    }
+}
+
+void 
celix_frameworkConditions_registerFrameworkReadyConditions(celix_framework_t* 
framework) {
+    //note called when all bundles are installed and started
+    celix_frameworkConditions_checkFrameworkReady(framework);
+}
+
+void 
celix_frameworkConditions_unregisterFrameworkReadyConditions(celix_framework_t* 
framework) {
+    celix_bundle_context_t* ctx = 
celix_framework_getFrameworkContext(framework);
+    celixThreadMutex_lock(&framework->conditions.mutex);
+    for (int i = 0; i < 
celix_arrayList_size(framework->conditions.frameworkReadyConditionSvcIds); ++i) 
{
+        long svcId = 
(long)celix_arrayList_get(framework->conditions.frameworkReadyConditionSvcIds, 
i);
+        celix_bundleContext_unregisterServiceAsync(ctx, svcId, NULL, NULL);
+    }
+    celix_arrayList_clear(framework->conditions.frameworkReadyConditionSvcIds);
+    celixThreadMutex_unlock(&framework->conditions.mutex);
+}
\ No newline at end of file
diff --git a/libs/framework/src/celix_framework_conditions.h 
b/libs/framework/src/celix_framework_conditions.h
new file mode 100644
index 00000000..cf9c14ff
--- /dev/null
+++ b/libs/framework/src/celix_framework_conditions.h
@@ -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.
+*/
+
+#ifndef CELIX_CELIX_FRAMEWORK_CONDITIONS_H_
+#define CELIX_CELIX_FRAMEWORK_CONDITIONS_H_
+
+#include "celix_types.h"
+#include "celix_errno.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Register the initial celix_condition services for the framework.
+ *
+ * The initial celix_condition services are:
+ * - The true celix_condition service
+ *
+ * Will log an error if the initial celix_condition services administration 
objects or services registrations
+ * fail.
+ *
+ * @param[in] framework The framework.
+ */
+void celix_frameworkConditions_registerInitialConditions(celix_framework_t* 
framework);
+
+/**
+ * @brief Unregister the initial celix_condition services for the framework.
+ * @param[in] framework The framework.
+ */
+void celix_frameworkConditions_unregisterInitialConditions(celix_framework_t* 
framework);
+
+/**
+ * @brief Register the framework ready celix_condition services for the 
framework.
+ *
+ * The framework ready celix_condition services are:
+ * - The framework.ready celix_condition service
+ *
+ * Will log an error if the framework read celix_condition services 
administration objects or services registrations
+ * fail.
+ *
+ * @param framework The framework.
+ */
+void 
celix_frameworkConditions_registerFrameworkReadyConditions(celix_framework_t* 
framework);
+
+/**
+ * @brief Unregister the framework ready celix_condition services for the 
framework.
+ * @param framework The framework.
+ */
+void 
celix_frameworkConditions_unregisterFrameworkReadyConditions(celix_framework_t* 
framework);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CELIX_CELIX_FRAMEWORK_CONDITIONS_H_
diff --git a/libs/framework/src/framework.c b/libs/framework/src/framework.c
index 0a2d1dc6..8962d0f8 100644
--- a/libs/framework/src/framework.c
+++ b/libs/framework/src/framework.c
@@ -36,6 +36,7 @@
 #include "celix_libloader.h"
 #include "celix_log_constants.h"
 #include "celix_module_private.h"
+#include "celix_framework_conditions.h"
 
 #include "bundle_archive_private.h"
 #include "bundle_context_private.h"
@@ -176,10 +177,10 @@ static celix_status_t frameworkActivator_start(void * 
userData, bundle_context_t
 static celix_status_t frameworkActivator_stop(void * userData, 
bundle_context_t *context);
 static celix_status_t frameworkActivator_destroy(void * userData, 
bundle_context_t *context);
 
-static void framework_autoStartConfiguredBundles(celix_framework_t *fw);
-static void framework_autoInstallConfiguredBundles(celix_framework_t *fw);
-static void framework_autoInstallConfiguredBundlesForList(celix_framework_t 
*fw, const char *autoStart, celix_array_list_t *installedBundles);
-static void framework_autoStartConfiguredBundlesForList(celix_framework_t* fw, 
const celix_array_list_t *installedBundles);
+static celix_status_t framework_autoStartConfiguredBundles(celix_framework_t 
*fw);
+static celix_status_t framework_autoInstallConfiguredBundles(celix_framework_t 
*fw);
+static celix_status_t 
framework_autoInstallConfiguredBundlesForList(celix_framework_t *fw, const char 
*autoStart, celix_array_list_t *installedBundles);
+static celix_status_t 
framework_autoStartConfiguredBundlesForList(celix_framework_t* fw, const 
celix_array_list_t *installedBundles);
 static void celix_framework_addToEventQueue(celix_framework_t *fw, const 
celix_framework_event_t* event);
 
 struct fw_bundleListener {
@@ -255,6 +256,10 @@ celix_status_t framework_create(framework_pt *out, 
celix_properties_t* config) {
     framework->dispatcher.eventQueue = malloc(sizeof(celix_framework_event_t) 
* framework->dispatcher.eventQueueCap);
     framework->dispatcher.dynamicEventQueue = celix_arrayList_create();
 
+    celixThreadMutex_create(&framework->conditions.mutex, NULL);
+    framework->conditions.initialConditionSvcIds = celix_arrayList_create();
+    framework->conditions.frameworkReadyConditionSvcIds = 
celix_arrayList_create();
+
     //create and store framework uuid
     char uuid[37];
     uuid_t uid;
@@ -456,47 +461,59 @@ celix_status_t fw_init(framework_pt framework) {
        return status;
 }
 
-celix_status_t framework_start(framework_pt framework) {
-       celix_status_t status = CELIX_SUCCESS;
-       bundle_state_e state = CELIX_BUNDLE_STATE_UNKNOWN;
+celix_status_t framework_start(celix_framework_t* framework) {
+    celix_status_t status = CELIX_SUCCESS;
+    bundle_state_e state = CELIX_BUNDLE_STATE_UNKNOWN;
 
-       status = CELIX_DO_IF(status, bundle_getState(framework->bundle, 
&state));
-       if (status == CELIX_SUCCESS) {
-           if ((state == CELIX_BUNDLE_STATE_INSTALLED) || (state == 
CELIX_BUNDLE_STATE_RESOLVED)) {
-               status = CELIX_DO_IF(status, fw_init(framework));
+    status = CELIX_DO_IF(status, bundle_getState(framework->bundle, &state));
+    if (status == CELIX_SUCCESS) {
+        if ((state == CELIX_BUNDLE_STATE_INSTALLED) || (state == 
CELIX_BUNDLE_STATE_RESOLVED)) {
+            status = CELIX_DO_IF(status, fw_init(framework));
         }
-       }
+    }
 
-       status = CELIX_DO_IF(status, bundle_getState(framework->bundle, 
&state));
-       if (status == CELIX_SUCCESS && state == CELIX_BUNDLE_STATE_STARTING) {
+    status = CELIX_DO_IF(status, bundle_getState(framework->bundle, &state));
+    if (status == CELIX_SUCCESS && state == CELIX_BUNDLE_STATE_STARTING) {
         bundle_setState(framework->bundle, CELIX_BUNDLE_STATE_ACTIVE);
-       }
+    }
 
-       celix_framework_bundle_entry_t* entry = 
celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(framework,
-                                                                               
                           framework->bundleId);
-       CELIX_DO_IF(status, fw_fireBundleEvent(framework, 
OSGI_FRAMEWORK_BUNDLE_EVENT_STARTED, entry));
+    celix_framework_bundle_entry_t* entry =
+        
celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(framework, 
framework->bundleId);
+    CELIX_DO_IF(status, fw_fireBundleEvent(framework, 
OSGI_FRAMEWORK_BUNDLE_EVENT_STARTED, entry));
     celix_framework_bundleEntry_decreaseUseCount(entry);
 
-       CELIX_DO_IF(status, fw_fireFrameworkEvent(framework, 
OSGI_FRAMEWORK_EVENT_STARTED, framework->bundleId));
+    celix_frameworkConditions_registerInitialConditions(framework);
+    CELIX_DO_IF(status, fw_fireFrameworkEvent(framework, 
OSGI_FRAMEWORK_EVENT_STARTED, framework->bundleId));
 
-       if (status != CELIX_SUCCESS) {
-       status = CELIX_BUNDLE_EXCEPTION;
-       fw_logCode(framework->logger, CELIX_LOG_LEVEL_ERROR, status, "Could not 
start framework");
-       fw_fireFrameworkEvent(framework, OSGI_FRAMEWORK_EVENT_ERROR, status);
+    if (status != CELIX_SUCCESS) {
+        status = CELIX_BUNDLE_EXCEPTION;
+        fw_logCode(framework->logger, CELIX_LOG_LEVEL_ERROR, status, "Could 
not start framework");
+        fw_fireFrameworkEvent(framework, OSGI_FRAMEWORK_EVENT_ERROR, status);
     }
 
-    framework_autoStartConfiguredBundles(framework);
-    framework_autoInstallConfiguredBundles(framework);
+    celix_status_t startStatus = 
framework_autoStartConfiguredBundles(framework);
+    celix_status_t installStatus = 
framework_autoInstallConfiguredBundles(framework);
+    if (startStatus == CELIX_SUCCESS && installStatus == CELIX_SUCCESS) {
+        celix_frameworkConditions_registerFrameworkReadyConditions(framework);
+    } else {
+        status = CELIX_BUNDLE_EXCEPTION; //error already logged
+    }
 
-       if (status == CELIX_SUCCESS) {
+    if (status == CELIX_SUCCESS) {
         fw_log(framework->logger, CELIX_LOG_LEVEL_INFO, "Celix framework 
started");
-        fw_log(framework->logger, CELIX_LOG_LEVEL_TRACE, "Celix framework 
started with uuid %s", celix_framework_getUUID(framework));
-       }
+        fw_log(framework->logger,
+               CELIX_LOG_LEVEL_TRACE,
+               "Celix framework started with uuid %s",
+               celix_framework_getUUID(framework));
+    } else {
+        fw_log(framework->logger, CELIX_LOG_LEVEL_ERROR, "Celix framework 
failed to start");
+    }
 
-       return status;
+    return status;
 }
 
-static void framework_autoStartConfiguredBundles(celix_framework_t* fw) {
+static celix_status_t framework_autoStartConfiguredBundles(celix_framework_t* 
fw) {
+    celix_status_t status = CELIX_SUCCESS;
     const char* const cosgiKeys[] = 
{"cosgi.auto.start.0","cosgi.auto.start.1","cosgi.auto.start.2","cosgi.auto.start.3","cosgi.auto.start.4","cosgi.auto.start.5","cosgi.auto.start.6",
 NULL};
     const char* const celixKeys[] = {CELIX_AUTO_START_0, CELIX_AUTO_START_1, 
CELIX_AUTO_START_2, CELIX_AUTO_START_3, CELIX_AUTO_START_4, CELIX_AUTO_START_5, 
CELIX_AUTO_START_6, NULL};
     CELIX_BUILD_ASSERT(sizeof(*cosgiKeys) == sizeof(*celixKeys));
@@ -507,22 +524,30 @@ static void 
framework_autoStartConfiguredBundles(celix_framework_t* fw) {
             autoStart = celix_framework_getConfigProperty(fw, cosgiKeys[i], 
NULL, NULL);
         }
         if (autoStart != NULL) {
-            framework_autoInstallConfiguredBundlesForList(fw, autoStart, 
installedBundles);
+            if (framework_autoInstallConfiguredBundlesForList(fw, autoStart, 
installedBundles) != CELIX_SUCCESS) {
+                status = CELIX_BUNDLE_EXCEPTION;
+            }
         }
     }
-    framework_autoStartConfiguredBundlesForList(fw, installedBundles);
+    celix_status_t startStatus = 
framework_autoStartConfiguredBundlesForList(fw, installedBundles);
+    if (status == CELIX_SUCCESS) {
+        status = startStatus;
+    }
     celix_arrayList_destroy(installedBundles);
+    return status;
 }
 
-static void framework_autoInstallConfiguredBundles(celix_framework_t* fw) {
+static celix_status_t 
framework_autoInstallConfiguredBundles(celix_framework_t* fw) {
     const char* autoInstall = celix_framework_getConfigProperty(fw, 
CELIX_AUTO_INSTALL, NULL, NULL);
     if (autoInstall != NULL) {
-        framework_autoInstallConfiguredBundlesForList(fw, autoInstall, NULL);
+        return framework_autoInstallConfiguredBundlesForList(fw, autoInstall, 
NULL);
     }
+    return CELIX_SUCCESS;
 }
 
 
-static void framework_autoInstallConfiguredBundlesForList(celix_framework_t* 
fw, const char *autoStartIn, celix_array_list_t *installedBundles) {
+static celix_status_t 
framework_autoInstallConfiguredBundlesForList(celix_framework_t* fw, const char 
*autoStartIn, celix_array_list_t *installedBundles) {
+    celix_status_t status = CELIX_SUCCESS;
     char delims[] = " ";
     char *save_ptr = NULL;
     char autoStartBuffer[CELIX_DEFAULT_STRING_CREATE_BUFFER_SIZE];
@@ -538,6 +563,7 @@ static void 
framework_autoInstallConfiguredBundlesForList(celix_framework_t* fw,
                 }
             } else {
                 fw_log(fw->logger, CELIX_LOG_LEVEL_ERROR, "Could not install 
bundle from location '%s'.", location);
+                status = CELIX_BUNDLE_EXCEPTION;
             }
             location = strtok_r(NULL, delims, &save_ptr);
         }
@@ -545,9 +571,11 @@ static void 
framework_autoInstallConfiguredBundlesForList(celix_framework_t* fw,
         fw_log(fw->logger, CELIX_LOG_LEVEL_ERROR, "Could not auto install 
bundles, out of memory.");
     }
     celix_utils_freeStringIfNotEqual(autoStartBuffer, autoStart);
+    return status;;
 }
 
-static void framework_autoStartConfiguredBundlesForList(celix_framework_t* fw, 
const celix_array_list_t *installedBundles) {
+static celix_status_t 
framework_autoStartConfiguredBundlesForList(celix_framework_t* fw, const 
celix_array_list_t *installedBundles) {
+    celix_status_t status = CELIX_SUCCESS;
     assert(!celix_framework_isCurrentThreadTheEventLoop(fw));
     for (int i = 0; i < celix_arrayList_size(installedBundles); ++i) {
         long bndId = celix_arrayList_getLong(installedBundles, i);
@@ -559,8 +587,10 @@ static void 
framework_autoStartConfiguredBundlesForList(celix_framework_t* fw, c
             }
         } else {
             fw_log(fw->logger, CELIX_LOG_LEVEL_TRACE, "Cannot start bundle %s 
(bnd id = %li), because it is already started\n", bnd->symbolicName, bndId);
+            status = CELIX_BUNDLE_EXCEPTION;
         }
     }
+    return status;
 }
 
 celix_status_t framework_stop(framework_pt framework) {
@@ -1177,7 +1207,6 @@ static void* framework_shutdown(void *framework) {
     }
     celixThreadMutex_unlock(&fw->installedBundles.mutex);
 
-
     size = celix_arrayList_size(stopEntries);
     for (int i = size-1; i >= 0; --i) { //note loop in reverse order -> stop 
later installed bundle first
         celix_framework_bundle_entry_t *entry = 
celix_arrayList_get(stopEntries, i);
@@ -1196,7 +1225,6 @@ static void* framework_shutdown(void *framework) {
     }
     celix_arrayList_destroy(stopEntries);
 
-
     // 'stop' framework bundle
     if (fwEntry != NULL) {
         bundle_t *bnd = fwEntry->bnd;
@@ -1494,8 +1522,10 @@ static celix_status_t frameworkActivator_stop(void * 
userData, bundle_context_t
 
     if (bundleContext_getFramework(context, &framework) == CELIX_SUCCESS) {
 
-        fw_log(framework->logger, CELIX_LOG_LEVEL_TRACE, "Start shutdown 
thread for framework %s", celix_framework_getUUID(framework));
+        
celix_frameworkConditions_unregisterFrameworkReadyConditions(framework);
+        celix_frameworkConditions_unregisterInitialConditions(framework);
 
+        fw_log(framework->logger, CELIX_LOG_LEVEL_TRACE, "Start shutdown 
thread for framework %s", celix_framework_getUUID(framework));
         celixThreadMutex_lock(&framework->shutdown.mutex);
         bool alreadyInitialized = framework->shutdown.initialized;
         framework->shutdown.initialized = true;
diff --git a/libs/framework/src/framework_private.h 
b/libs/framework/src/framework_private.h
index d2a36cfc..a06a8c3b 100644
--- a/libs/framework/src/framework_private.h
+++ b/libs/framework/src/framework_private.h
@@ -188,6 +188,12 @@ struct celix_framework {
         celix_thread_mutex_t mutex; //protects below
         celix_array_list_t* bundleLifecycleHandlers; //entry = 
celix_framework_bundle_lifecycle_handler_t*
     } bundleLifecycleHandling;
+
+    struct {
+        celix_thread_mutex_t mutex; /**< protects below*/
+        celix_array_list_t* initialConditionSvcIds; /**< entry = long (service 
id) */
+        celix_array_list_t* frameworkReadyConditionSvcIds; /**< entry = long 
(service id) */
+    } conditions; /**< Struct to store the framework celix_conditions admin */
 };
 
 /**

Reply via email to