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

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

commit 52d72cf73d53372f98cf5ef58652cb60c8070945
Author: Pepijn Noltes <[email protected]>
AuthorDate: Tue Dec 21 20:17:19 2021 +0100

    Reintroduces a way to install - but not start - bundles with a 
config/containers.
    
    Also introduces a celix_ api to query installed bundle ids.
---
 cmake/cmake_celix/ContainerPackaging.cmake         | 29 ++++++--
 documents/cmake_commands/README.md                 | 67 +++++++++++-------
 .../celix-examples/http_example/CMakeLists.txt     |  6 +-
 libs/framework/gtest/CMakeLists.txt                | 44 ++++++++----
 .../gtest/install_and_start_bundles.properties.in  | 28 ++++++++
 .../gtest/src/CxxBundleContextTestSuite.cc         |  8 ++-
 .../gtest/src/bundle_context_bundles_tests.cpp     | 12 ++--
 libs/framework/gtest/src/single_framework_test.cpp | 80 ++++++++++++++++++++++
 libs/framework/include/celix/BundleContext.h       | 35 +++++++---
 libs/framework/include/celix/Constants.h           | 12 ++++
 libs/framework/include/celix_bundle_context.h      | 12 +++-
 libs/framework/include/celix_constants.h           | 13 ++++
 libs/framework/include/celix_framework.h           | 21 +++++-
 libs/framework/src/bundle_context.c                | 14 ++--
 libs/framework/src/framework.c                     | 50 ++++++++++++--
 15 files changed, 353 insertions(+), 78 deletions(-)

diff --git a/cmake/cmake_celix/ContainerPackaging.cmake 
b/cmake/cmake_celix/ContainerPackaging.cmake
index 60c2bd4..d034799 100644
--- a/cmake/cmake_celix/ContainerPackaging.cmake
+++ b/cmake/cmake_celix/ContainerPackaging.cmake
@@ -67,8 +67,9 @@ Optional Arguments:
 - GROUP: If configured the build location will be prefixed the GROUP. Default 
is empty.
 - NAME: The name of the executable. Default is <celix_container_name>. Only 
useful for generated/LAUNCHER_SRC Celix launchers.
 - DIR: The base build directory of the Celix container. Default is 
`<cmake_build_dir>/deploy`.
-- BUNDLES: A list of bundles to configured for the Celix container to install 
and start.
+- BUNDLES: A list of bundles for the Celix container to install and start.
   These bundle will be configured for run level 3. See 
'celix_container_bundles' for more info.
+- INSTALL_BUNDLES: A list of bundles for the Celix container to install (but 
not start).
 - PROPERTIES: A list of configuration properties, these can be used to 
configure the Celix framework and/or bundles.
   Normally this will be EMBEDED_PROPERTIES, but if the USE_CONFIG option is 
used this will be RUNTIME_PROPERTIES.
   See the framework library or bundles documentation about the available 
configuration options.
@@ -86,6 +87,7 @@ add_celix_container(<celix_container_name>
     [NAME celix_container_name]
     [DIR dir]
     [BUNDLES <bundle1> <bundle2> ...]
+    [INSTALL_BUNDLES <bundle1> <bundle2> ...]
     [PROPERTIES "prop1=val1" "prop2=val2" ...]
     [EMBEDDED_PROPERTIES "prop1=val1" "prop2=val2" ...]
     [RUNTIME_PROPERTIES "prop1=val1" "prop2=val2" ...]
@@ -104,6 +106,7 @@ add_celix_container(<celix_container_name>
     [NAME celix_container_name]
     [DIR dir]
     [BUNDLES <bundle1> <bundle2> ...]
+    [INSTALL_BUNDLES <bundle1> <bundle2> ...]
     [PROPERTIES "prop1=val1" "prop2=val2" ...]
     [EMBEDDED_PROPERTIES "prop1=val1" "prop2=val2" ...]
     [RUNTIME_PROPERTIES "prop1=val1" "prop2=val2" ...]
@@ -122,6 +125,7 @@ add_celix_container(<celix_container_name>
     [NAME celix_container_name]
     [DIR dir]
     [BUNDLES <bundle1> <bundle2> ...]
+    [INSTALL_BUNDLES <bundle1> <bundle2> ...]
     [PROPERTIES "prop1=val1" "prop2=val2" ...]
     [EMBEDDED_PROPERTIES "prop1=val1" "prop2=val2" ...]
     [RUNTIME_PROPERTIES "prop1=val1" "prop2=val2" ...]
@@ -134,7 +138,7 @@ function(add_celix_container)
 
     set(OPTIONS COPY C CXX USE_CONFIG)
     set(ONE_VAL_ARGS GROUP NAME LAUNCHER LAUNCHER_SRC DIR)
-    set(MULTI_VAL_ARGS BUNDLES PROPERTIES EMBEDDED_PROPERTIES 
RUNTIME_PROPERTIES)
+    set(MULTI_VAL_ARGS BUNDLES INSTALL_BUNDLES PROPERTIES EMBEDDED_PROPERTIES 
RUNTIME_PROPERTIES)
     cmake_parse_arguments(CONTAINER "${OPTIONS}" "${ONE_VAL_ARGS}" 
"${MULTI_VAL_ARGS}" ${ARGN})
 
     ##### Check arguments #####
@@ -203,6 +207,7 @@ 
$<$<BOOL:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_LEVEL_3>>:CELIX
 
$<$<BOOL:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_LEVEL_4>>:CELIX_AUTO_START_4=$<JOIN:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_LEVEL_4>,
 >\\n>\\
 
$<$<BOOL:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_LEVEL_5>>:CELIX_AUTO_START_5=$<JOIN:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_LEVEL_5>,
 >\\n>\\
 
$<$<BOOL:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_LEVEL_6>>:CELIX_AUTO_START_6=$<JOIN:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_LEVEL_6>,
 >\\n>\\
+$<$<BOOL:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_INSTALL>>:CELIX_AUTO_INSTALL=$<JOIN:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_INSTALL>,
 >\\n>\\
 
$<JOIN:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_EMBEDDED_PROPERTIES>,\\n\\
 >\";
 
@@ -248,6 +253,7 @@ 
$<$<BOOL:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_LEVEL_3>>:CELIX
 
$<$<BOOL:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_LEVEL_4>>:CELIX_AUTO_START_4=$<JOIN:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_LEVEL_4>,
 >>
 
$<$<BOOL:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_LEVEL_5>>:CELIX_AUTO_START_5=$<JOIN:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_LEVEL_5>,
 >>
 
$<$<BOOL:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_LEVEL_6>>:CELIX_AUTO_START_6=$<JOIN:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_LEVEL_6>,
 >>
+$<$<BOOL:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_INSTALL>>:CELIX_AUTO_INSTALL=$<JOIN:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_BUNDLES_INSTALL>,
 >>
 $<JOIN:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_RUNTIME_PROPERTIES>,
 >"
         )
@@ -313,6 +319,7 @@ 
$<JOIN:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_RUNTIME_PROPERTIES>,
     set_target_properties(${CONTAINER_TARGET} PROPERTIES 
"CONTAINER_BUNDLES_LEVEL_4" "") #bundles to deploy for the container for 
startup level 4
     set_target_properties(${CONTAINER_TARGET} PROPERTIES 
"CONTAINER_BUNDLES_LEVEL_5" "") #bundles to deploy for the container for 
startup level 5
     set_target_properties(${CONTAINER_TARGET} PROPERTIES 
"CONTAINER_BUNDLES_LEVEL_6" "") #bundles to deploy for the container for 
startup level 6
+    set_target_properties(${CONTAINER_TARGET} PROPERTIES 
"CONTAINER_BUNDLES_INSTALL" "") #bundles to install for the container
     set_target_properties(${CONTAINER_TARGET} PROPERTIES 
"CONTAINER_COPY_BUNDLES" ${CONTAINER_COPY}) #copy bundles in bundle dir or link 
using abs paths. NOTE this cannot be changed after a add_deploy command
 
     #deploy specific
@@ -325,6 +332,7 @@ 
$<JOIN:$<TARGET_PROPERTY:${CONTAINER_TARGET},CONTAINER_RUNTIME_PROPERTIES>,
     #####
 
     celix_container_bundles(${CONTAINER_TARGET} LEVEL 3 ${CONTAINER_BUNDLES})
+    celix_container_bundles(${CONTAINER_TARGET} INSTALL 
${CONTAINER_INSTALL_BUNDLES})
     if (CONTAINER_USE_CONFIG)
         celix_container_runtime_properties(${CONTAINER_TARGET} 
${CONTAINER_PROPERTIES})
     else ()
@@ -446,10 +454,13 @@ Within a run level the order of configured decides the 
start order; bundles adde
 
 Optional Arguments:
 - LEVEL: The run level for the added bundles. Default is 3.
+- INSTALL: If this option is present, the bundles will only be installed 
instead of the default install and start.
+           The bundles will be installed after all bundle in LEVEL 0..6 are 
installed and started.
 
 ```CMake
 celix_container_bundles(<celix_container_target_name>
     [LEVEL (0..6)]
+    [INSTALL]
     bundle1
     bundle2
     ...
@@ -462,7 +473,7 @@ function(celix_container_bundles)
     list(GET ARGN 0 CONTAINER_TARGET)
     list(REMOVE_AT ARGN 0)
 
-    set(OPTIONS )
+    set(OPTIONS INSTALL)
     set(ONE_VAL_ARGS LEVEL)
     set(MULTI_VAL_ARGS )
     cmake_parse_arguments(BUNDLES "${OPTIONS}" "${ONE_VAL_ARGS}" 
"${MULTI_VAL_ARGS}" ${ARGN})
@@ -472,7 +483,11 @@ function(celix_container_bundles)
         set(BUNDLES_LEVEL 3)
     endif ()
 
-    get_target_property(BUNDLES ${CONTAINER_TARGET} 
"CONTAINER_BUNDLES_LEVEL_${BUNDLES_LEVEL}")
+    if (BUNDLES_INSTALL)
+        get_target_property(BUNDLES ${CONTAINER_TARGET} 
"CONTAINER_BUNDLES_INSTALL")
+    else () #bundle level 0,1,2,3,4,5 or 6
+        get_target_property(BUNDLES ${CONTAINER_TARGET} 
"CONTAINER_BUNDLES_LEVEL_${BUNDLES_LEVEL}")
+    endif ()
     get_target_property(COPY ${CONTAINER_TARGET} "CONTAINER_COPY_BUNDLES")
     get_target_property(DEPS ${CONTAINER_TARGET} "CONTAINER_TARGET_DEPS")
 
@@ -521,7 +536,11 @@ function(celix_container_bundles)
            endif()
    endforeach()
 
-    set_target_properties(${CONTAINER_TARGET} PROPERTIES 
"CONTAINER_BUNDLES_LEVEL_${BUNDLES_LEVEL}" "${BUNDLES}")
+    if (BUNDLES_INSTALL)
+        set_target_properties(${CONTAINER_TARGET} PROPERTIES 
"CONTAINER_BUNDLES_INSTALL" "${BUNDLES}")
+    else () #bundle level 0,1,2,3,4,5 or 6
+        set_target_properties(${CONTAINER_TARGET} PROPERTIES 
"CONTAINER_BUNDLES_LEVEL_${BUNDLES_LEVEL}" "${BUNDLES}")
+    endif ()
     set_target_properties(${CONTAINER_TARGET} PROPERTIES 
"CONTAINER_TARGET_DEPS" "${DEPS}")
 
    if(COPY) 
diff --git a/documents/cmake_commands/README.md 
b/documents/cmake_commands/README.md
index d6f79dd..21f4b8c 100644
--- a/documents/cmake_commands/README.md
+++ b/documents/cmake_commands/README.md
@@ -276,37 +276,47 @@ There are three variants of 'add_celix_container':
 - If no launcher is specified a custom Celix launcher will be generated. This 
launcher also contains the configured properties.
 - If a LAUNCHER_SRC is provided a Celix launcher will be build using the 
provided sources. Additional sources can be added with the
   CMake 'target_sources' command.
-- If a LAUNCHER (absolute path to a executable of CMake `add_executable` 
target) is provided that will be used as Celix launcher. 
+- If a LAUNCHER (absolute path to a executable of CMake `add_executable` 
target) is provided that will be used as Celix launcher.
 
 Creating a Celix containers using 'add_celix_container' will lead to a CMake 
executable target (expect if a LAUNCHER is used).
 These targets can be used to run/debug Celix containers from a IDE (if the IDE 
supports CMake).
 
 Optional Arguments:
-- COPY: With this option the used bundles are copied to the container build 
dir in the 'bundles' dir.  
-  A additional result of this is that the configured references to the bundles 
are then relative instead of absolute. 
-- CXX: With this option the generated Celix launcher (if used) will be a C++ 
source instead of a C source. 
-  A additional result of this is that Celix launcher is also linked against 
stdlibc++.
+- COPY: With this option the used bundles are copied to the container build 
dir in the 'bundles' dir.
+  A additional result of this is that the configured references to the bundles 
are then relative instead of absolute.
+  Default is COPY
+- NO_COPY: With this option the used bundles configured for the container with 
absolute paths.
+  Default is COPY
+- CXX: With this option the generated Celix launcher (if used) will be a C++ 
source. (Default is CXX)
+  This ensures that the Celix launcher is linked against stdlibc++.
+  Default is CXX
+- C: With this option the generated Celix launcher (if used) will be a C 
source.
+  Default is CXX
 - USE_CONFIG: With this option config properties are generated in a 
'config.properties' instead of embedded in the Celix launcher.
 - GROUP: If configured the build location will be prefixed the GROUP. Default 
is empty.
 - NAME: The name of the executable. Default is <celix_container_name>. Only 
useful for generated/LAUNCHER_SRC Celix launchers.
 - DIR: The base build directory of the Celix container. Default is 
`<cmake_build_dir>/deploy`.
-- BUNDLES: A list of bundles to configured for the Celix container to install 
and start. 
+- BUNDLES: A list of bundles for the Celix container to install and start.
   These bundle will be configured for run level 3. See 
'celix_container_bundles' for more info.
-- PROPERTIES: A list of configuration properties, these can be used to 
configure the Celix framework and/or bundles. 
-  Normally this will be EMBEDED_PROPERTIES, but if the USE_CONFIG option is 
used this will be RUNTIME_PROPERTIES. 
+- INSTALL_BUNDLES: A list of bundles for the Celix container to install (but 
not start).
+- PROPERTIES: A list of configuration properties, these can be used to 
configure the Celix framework and/or bundles.
+  Normally this will be EMBEDED_PROPERTIES, but if the USE_CONFIG option is 
used this will be RUNTIME_PROPERTIES.
   See the framework library or bundles documentation about the available 
configuration options.
-- EMBEDDED_PROPERTIES: A list of configuration properties which will be used 
in the generated Celix launcher. 
+- EMBEDDED_PROPERTIES: A list of configuration properties which will be used 
in the generated Celix launcher.
 - RUNTIME_PROPERTIES: A list of configuration properties which will be used in 
the generated config.properties file.
 
 ```CMake
 add_celix_container(<celix_container_name>
     [COPY]
+    [NO_COPY]
     [CXX]
+    [C]
     [USE_CONFIG]
     [GROUP group_name]
     [NAME celix_container_name]
     [DIR dir]
     [BUNDLES <bundle1> <bundle2> ...]
+    [INSTALL_BUNDLES <bundle1> <bundle2> ...]
     [PROPERTIES "prop1=val1" "prop2=val2" ...]
     [EMBEDDED_PROPERTIES "prop1=val1" "prop2=val2" ...]
     [RUNTIME_PROPERTIES "prop1=val1" "prop2=val2" ...]
@@ -317,12 +327,15 @@ add_celix_container(<celix_container_name>
 add_celix_container(<celix_container_name>
     LAUNCHER launcher
     [COPY]
+    [NO_COPY]
     [CXX]
+    [C]
     [USE_CONFIG]
     [GROUP group_name]
     [NAME celix_container_name]
     [DIR dir]
     [BUNDLES <bundle1> <bundle2> ...]
+    [INSTALL_BUNDLES <bundle1> <bundle2> ...]
     [PROPERTIES "prop1=val1" "prop2=val2" ...]
     [EMBEDDED_PROPERTIES "prop1=val1" "prop2=val2" ...]
     [RUNTIME_PROPERTIES "prop1=val1" "prop2=val2" ...]
@@ -331,36 +344,42 @@ add_celix_container(<celix_container_name>
 
 ```CMake
 add_celix_container(<celix_container_name>
-    LAUNCHER_SRC launcher_src
-    [COPY]
-    [CXX]
-    [USE_CONFIG]
-    [GROUP group_name]
-    [NAME celix_container_name]
-    [DIR dir]
-    [BUNDLES <bundle1> <bundle2> ...]
-    [PROPERTIES "prop1=val1" "prop2=val2" ...]
-    [EMBEDDED_PROPERTIES "prop1=val1" "prop2=val2" ...]
-    [RUNTIME_PROPERTIES "prop1=val1" "prop2=val2" ...]
-)
+        LAUNCHER_SRC launcher_src
+        [COPY]
+        [NO_COPY]
+        [CXX]
+        [C]
+        [USE_CONFIG]
+        [GROUP group_name]
+        [NAME celix_container_name]
+        [DIR dir]
+        [BUNDLES <bundle1> <bundle2> ...]
+        [INSTALL_BUNDLES <bundle1> <bundle2> ...]
+        [PROPERTIES "prop1=val1" "prop2=val2" ...]
+        [EMBEDDED_PROPERTIES "prop1=val1" "prop2=val2" ...]
+        [RUNTIME_PROPERTIES "prop1=val1" "prop2=val2" ...]
+        )
 ```
 
 ## celix_container_bundles
 Add the selected bundles to the Celix container. These bundles are (if 
configured) copied to the container build dir and
 are added to the configuration properties so that they are installed and 
started when the Celix container executed.
 
-The Celix framework support 7 (0 - 6) run levels. Run levels can be used to 
control the start and stop order of bundles.
-Bundles in run level 0 are started first and bundles in run level 6 are 
started last. 
+The Celix framework supports 7 (0 - 6) run levels. Run levels can be used to 
control the start and stop order of bundles.
+Bundles in run level 0 are started first and bundles in run level 6 are 
started last.
 When stopping bundles in run level 6 are stopped first and bundles in run 
level 0 are stopped last.
 Within a run level the order of configured decides the start order; bundles 
added earlier are started first.
 
 
 Optional Arguments:
 - LEVEL: The run level for the added bundles. Default is 3.
+- INSTALL: If this option is present, the bundles will only be installed 
instead of the default install and start.
+  The bundles will be installed after all bundle in LEVEL 0..6 are installed 
and started.
 
 ```CMake
 celix_container_bundles(<celix_container_target_name>
-    [LEVEL (0..5)]
+    [LEVEL (0..6)]
+    [INSTALL]
     bundle1
     bundle2
     ...
diff --git a/examples/celix-examples/http_example/CMakeLists.txt 
b/examples/celix-examples/http_example/CMakeLists.txt
index 03bfad6..a52b8c9 100644
--- a/examples/celix-examples/http_example/CMakeLists.txt
+++ b/examples/celix-examples/http_example/CMakeLists.txt
@@ -35,10 +35,10 @@ if (TARGET Celix::http_admin AND TARGET Celix::shell AND 
TARGET Celix::shell_wui
             BUNDLES
                 Celix::http_admin
                 Celix::shell
-                Celix::shell_wui
+                Celix::shell_wui #web ui (webpage to access Celix shell using 
static html + websocket)
+                Celix::shell_tui #text ui (uses console at access Celix shell)
+            #INSTALL_BUNDLES #Enabled if you want to manually start the 
http_example bundle using the shell: `start 5`
                 http_example
-            PROPERTIES
-            #SHELL_USE_ANSI_COLORS=false
     )
 
 endif ()
diff --git a/libs/framework/gtest/CMakeLists.txt 
b/libs/framework/gtest/CMakeLists.txt
index 7c19404..d08796f 100644
--- a/libs/framework/gtest/CMakeLists.txt
+++ b/libs/framework/gtest/CMakeLists.txt
@@ -28,15 +28,15 @@ add_celix_bundle(simple_cxx_dep_man_bundle SOURCES 
src/HelloWorldCxxActivatorWit
 add_celix_bundle(cmp_test_bundle SOURCES src/CmpTestBundleActivator.cc)
 add_subdirectory(subdir) #simple_test_bundle4, simple_test_bundle5 and sublib
 
-add_celix_bundle(unresolveable_bundle SOURCES src/nop_activator.c VERSION 
1.0.0)
+add_celix_bundle(unresolvable_bundle SOURCES src/nop_activator.c VERSION 1.0.0)
 if (CMAKE_BUILD_TYPE STREQUAL "Debug")
     set(POSTFIX ${CMAKE_DEBUG_POSTFIX})
 endif()
-target_link_libraries(unresolveable_bundle PRIVATE 
"-L${CMAKE_CURRENT_BINARY_DIR}/subdir -lsublib${POSTFIX}")
+target_link_libraries(unresolvable_bundle PRIVATE 
"-L${CMAKE_CURRENT_BINARY_DIR}/subdir -lsublib${POSTFIX}")
 if(NOT APPLE)
-    set_target_properties(unresolveable_bundle PROPERTIES LINK_FLAGS 
-Wl,--no-as-needed)
+    set_target_properties(unresolvable_bundle PROPERTIES LINK_FLAGS 
-Wl,--no-as-needed)
 endif()
-add_dependencies(unresolveable_bundle sublib)
+add_dependencies(unresolvable_bundle sublib)
 
 add_executable(test_framework
         src/single_framework_test.cpp
@@ -55,27 +55,41 @@ add_celix_bundle_dependencies(test_framework
         simple_test_bundle5 bundle_with_exception unresolveable_bundle 
simple_cxx)
 target_include_directories(test_framework PRIVATE ../src)
 
+celix_get_bundle_file(simple_test_bundle1 SIMPLE_TEST_BUNDLE1)
+celix_get_bundle_file(simple_test_bundle2 SIMPLE_TEST_BUNDLE2)
+celix_get_bundle_file(simple_test_bundle3 SIMPLE_TEST_BUNDLE3)
+celix_get_bundle_file(simple_test_bundle4 SIMPLE_TEST_BUNDLE4)
+celix_get_bundle_file(simple_test_bundle5 SIMPLE_TEST_BUNDLE5)
+celix_get_bundle_filename(simple_test_bundle4 SIMPLE_TEST_BUNDLE4_FILENAME)
+celix_get_bundle_filename(simple_test_bundle5 SIMPLE_TEST_BUNDLE5_FILENAME)
+
+celix_get_bundle_filename(bundle_with_exception BUNDLE_WITH_EXCEPTION)
+celix_get_bundle_filename(unresolvable_bundle UNRESOLVABLE_BUNDLE)
+
 celix_get_bundle_file(simple_cxx_bundle SIMPLE_CXX_BUNDLE_LOC)
 celix_get_bundle_file(simple_cxx_dep_man_bundle SIMPLE_CXX_DEP_MAN_BUNDLE_LOC)
 celix_get_bundle_file(cmp_test_bundle CMP_TEST_BUNDLE_LOC)
+
+configure_file(config.properties.in config.properties @ONLY)
+configure_file(framework1.properties.in framework1.properties @ONLY)
+configure_file(framework2.properties.in framework2.properties @ONLY)
+configure_file(install_and_start_bundles.properties.in 
install_and_start_bundles.properties @ONLY)
+
 target_compile_definitions(test_framework PRIVATE
-        
SIMPLE_TEST_BUNDLE1_LOCATION="$<TARGET_PROPERTY:simple_test_bundle1,BUNDLE_FILE>"
-        
SIMPLE_TEST_BUNDLE2_LOCATION="$<TARGET_PROPERTY:simple_test_bundle2,BUNDLE_FILE>"
-        
SIMPLE_TEST_BUNDLE3_LOCATION="$<TARGET_PROPERTY:simple_test_bundle3,BUNDLE_FILE>"
-        
SIMPLE_TEST_BUNDLE4_LOCATION="$<TARGET_PROPERTY:simple_test_bundle4,BUNDLE_FILENAME>"
-        
SIMPLE_TEST_BUNDLE5_LOCATION="$<TARGET_PROPERTY:simple_test_bundle5,BUNDLE_FILENAME>"
-        
TEST_BUNDLE_WITH_EXCEPTION_LOCATION="$<TARGET_PROPERTY:bundle_with_exception,BUNDLE_FILE>"
-        
TEST_BUNDLE_UNRESOLVEABLE_LOCATION="$<TARGET_PROPERTY:unresolveable_bundle,BUNDLE_FILE>"
+        SIMPLE_TEST_BUNDLE1_LOCATION="${SIMPLE_TEST_BUNDLE1}"
+        SIMPLE_TEST_BUNDLE2_LOCATION="${SIMPLE_TEST_BUNDLE2}"
+        SIMPLE_TEST_BUNDLE3_LOCATION="${SIMPLE_TEST_BUNDLE3}"
+        SIMPLE_TEST_BUNDLE4_LOCATION="${SIMPLE_TEST_BUNDLE4_FILENAME}"
+        SIMPLE_TEST_BUNDLE5_LOCATION="${SIMPLE_TEST_BUNDLE5_FILENAME}"
+        TEST_BUNDLE_WITH_EXCEPTION_LOCATION="${BUNDLE_WITH_EXCEPTION}"
+        TEST_BUNDLE_UNRESOLVABLE_LOCATION="${UNRESOLVABLE_BUNDLE}"
         SIMPLE_CXX_BUNDLE_LOC="${SIMPLE_CXX_BUNDLE_LOC}"
         CMP_TEST_BUNDLE_LOC="${CMP_TEST_BUNDLE_LOC}"
         SIMPLE_CXX_DEP_MAN_BUNDLE_LOC="${SIMPLE_CXX_DEP_MAN_BUNDLE_LOC}"
         CMP_TEST_BUNDLE_LOC="${CMP_TEST_BUNDLE_LOC}"
+        
INSTALL_AND_START_BUNDLES_CONFIG_PROPERTIES_FILE="${CMAKE_CURRENT_BINARY_DIR}/install_and_start_bundles.properties"
 )
 
-configure_file(config.properties.in config.properties @ONLY)
-configure_file(framework1.properties.in framework1.properties @ONLY)
-configure_file(framework2.properties.in framework2.properties @ONLY)
-
 add_test(NAME test_framework COMMAND test_framework)
 setup_target_for_coverage(test_framework SCAN_DIR ..)
 
diff --git a/libs/framework/gtest/install_and_start_bundles.properties.in 
b/libs/framework/gtest/install_and_start_bundles.properties.in
new file mode 100644
index 0000000..ad52f2c
--- /dev/null
+++ b/libs/framework/gtest/install_and_start_bundles.properties.in
@@ -0,0 +1,28 @@
+# 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.
+
+
+#3 bundles, where 2 are valid and 1 non existing
+CELIX_AUTO_START_1=@SIMPLE_TEST_BUNDLE1@ @SIMPLE_TEST_BUNDLE2@ Invalid1.zip
+
+#3 bundles, 1 is valid, 1 non existing and 1 already started
+CELIX_AUTO_START_3=@SIMPLE_TEST_BUNDLE2@ @SIMPLE_TEST_BUNDLE3@ Invalid2.zip
+
+#4 bundles, 2 valid, 1 non existing and 1 already started
+CELIX_AUTO_INSTALL=@SIMPLE_TEST_BUNDLE3@ @SIMPLE_TEST_BUNDLE4@ 
@SIMPLE_TEST_BUNDLE5@ Invalid3.zip
+
+
diff --git a/libs/framework/gtest/src/CxxBundleContextTestSuite.cc 
b/libs/framework/gtest/src/CxxBundleContextTestSuite.cc
index f02114f..51446c5 100644
--- a/libs/framework/gtest/src/CxxBundleContextTestSuite.cc
+++ b/libs/framework/gtest/src/CxxBundleContextTestSuite.cc
@@ -392,12 +392,18 @@ TEST_F(CxxBundleContextTestSuite, 
OnRegisterAndUnregisterCallbacks) {
 
 TEST_F(CxxBundleContextTestSuite, InstallCxxBundle) {
     EXPECT_EQ(0, ctx->listBundleIds().size());
+    EXPECT_EQ(0, ctx->listInstalledBundleIds().size());
 
     std::string loc{SIMPLE_CXX_BUNDLE_LOC};
     ASSERT_FALSE(loc.empty());
-    long bndId = ctx->installBundle(loc);
+    long bndId = ctx->installBundle(loc, false);
     EXPECT_GE(bndId, 0);
+    EXPECT_EQ(0, ctx->listBundleIds().size());
+    EXPECT_EQ(1, ctx->listInstalledBundleIds().size());
+
+    ctx->startBundle(bndId);
     EXPECT_EQ(1, ctx->listBundleIds().size());
+    EXPECT_EQ(1, ctx->listInstalledBundleIds().size());
 }
 
 TEST_F(CxxBundleContextTestSuite, LoggingUsingContext) {
diff --git a/libs/framework/gtest/src/bundle_context_bundles_tests.cpp 
b/libs/framework/gtest/src/bundle_context_bundles_tests.cpp
index 8891411..0d3fc4d 100644
--- a/libs/framework/gtest/src/bundle_context_bundles_tests.cpp
+++ b/libs/framework/gtest/src/bundle_context_bundles_tests.cpp
@@ -41,7 +41,7 @@ public:
     const char * const TEST_BND4_LOC = "" SIMPLE_TEST_BUNDLE4_LOCATION "";
     const char * const TEST_BND5_LOC = "" SIMPLE_TEST_BUNDLE5_LOCATION "";
     const char * const TEST_BND_WITH_EXCEPTION_LOC = "" 
TEST_BUNDLE_WITH_EXCEPTION_LOCATION "";
-    const char * const TEST_BND_UNRESOLVEABLE_LOC = "" 
TEST_BUNDLE_UNRESOLVEABLE_LOCATION "";
+    const char * const TEST_BND_UNRESOLVABLE_LOC = "" 
TEST_BUNDLE_UNRESOLVABLE_LOCATION "";
 
     CelixBundleContextBundlesTests() {
         properties = properties_create();
@@ -175,7 +175,7 @@ TEST_F(CelixBundleContextBundlesTests, 
startBundleWithException) {
 }
 
 TEST_F(CelixBundleContextBundlesTests, startUnresolveableBundle) {
-    long bndId = celix_bundleContext_installBundle(ctx, 
TEST_BND_UNRESOLVEABLE_LOC, true);
+    long bndId = celix_bundleContext_installBundle(ctx, 
TEST_BND_UNRESOLVABLE_LOC, true);
     ASSERT_TRUE(bndId > 0); //bundle is installed, but not resolved
 
     bool called = celix_framework_useBundle(fw, false, bndId, nullptr, [](void 
*, const celix_bundle_t *bnd) {
@@ -218,9 +218,13 @@ TEST_F(CelixBundleContextBundlesTests, StopStartTest) {
     ASSERT_FALSE(celix_bundleContext_isBundleInstalled(ctx, 600 /*non 
existing*/));
 
 
+    celix_array_list_t *ids = celix_bundleContext_listInstalledBundles(ctx);
+    size_t size = celix_arrayList_size(ids);
+    ASSERT_EQ(3, size);
+    celix_arrayList_destroy(ids);
 
-    celix_array_list_t *ids = celix_bundleContext_listBundles(ctx);
-    size_t size = arrayList_size(ids);
+    ids = celix_bundleContext_listBundles(ctx);
+    size = celix_arrayList_size(ids);
     ASSERT_EQ(3, size);
 
     int count = 0;
diff --git a/libs/framework/gtest/src/single_framework_test.cpp 
b/libs/framework/gtest/src/single_framework_test.cpp
index 8765753..98e1dad 100644
--- a/libs/framework/gtest/src/single_framework_test.cpp
+++ b/libs/framework/gtest/src/single_framework_test.cpp
@@ -95,6 +95,52 @@ TEST_F(CelixFramework, 
testAsyncInstallStartStopAndUninstallBundle) {
     EXPECT_FALSE(celix_framework_isBundleInstalled(framework.get(), bndId));
 }
 
+TEST_F(CelixFramework, listBundles) {
+    auto list = celix_framework_listBundles(framework.get());
+    EXPECT_EQ(0, celix_arrayList_size(list));
+    celix_arrayList_destroy(list);
+    list = celix_framework_listInstalledBundles(framework.get());
+    EXPECT_EQ(0, celix_arrayList_size(list));
+    celix_arrayList_destroy(list);
+
+    long bndId = celix_framework_installBundle(framework.get(), 
SIMPLE_TEST_BUNDLE1_LOCATION, false);
+    EXPECT_GT(bndId, 0);
+
+    list = celix_framework_listBundles(framework.get());
+    EXPECT_EQ(0, celix_arrayList_size(list)); //installed, but not started
+    celix_arrayList_destroy(list);
+    list = celix_framework_listInstalledBundles(framework.get());
+    EXPECT_EQ(1, celix_arrayList_size(list));
+    celix_arrayList_destroy(list);
+
+    celix_framework_startBundle(framework.get(), bndId);
+
+    list = celix_framework_listBundles(framework.get());
+    EXPECT_EQ(1, celix_arrayList_size(list));
+    celix_arrayList_destroy(list);
+    list = celix_framework_listInstalledBundles(framework.get());
+    EXPECT_EQ(1, celix_arrayList_size(list));
+    celix_arrayList_destroy(list);
+
+    celix_framework_stopBundle(framework.get(), bndId);
+
+    list = celix_framework_listBundles(framework.get());
+    EXPECT_EQ(0, celix_arrayList_size(list));
+    celix_arrayList_destroy(list);
+    list = celix_framework_listInstalledBundles(framework.get());
+    EXPECT_EQ(1, celix_arrayList_size(list)); //stopped, but still installed
+    celix_arrayList_destroy(list);
+
+    celix_framework_uninstallBundle(framework.get(), bndId);
+
+    list = celix_framework_listBundles(framework.get());
+    EXPECT_EQ(0, celix_arrayList_size(list));
+    celix_arrayList_destroy(list);
+    list = celix_framework_listInstalledBundles(framework.get());
+    EXPECT_EQ(0, celix_arrayList_size(list));
+    celix_arrayList_destroy(list);
+}
+
 class FrameworkFactory : public ::testing::Test {
 public:
     FrameworkFactory() = default;
@@ -192,3 +238,37 @@ TEST_F(FrameworkFactory, restartFramework) {
     framework_destroy(fw);
 }
 
+
+TEST_F(CelixFramework, testLaunchFrameworkWithConfig) {
+    /* Rule: When a Celix framework is started with a config for auto starting 
bundles and installing bundles,
+     * the specified bundle are installed and if needed started.
+     */
+
+    auto* config = 
celix_properties_load(INSTALL_AND_START_BUNDLES_CONFIG_PROPERTIES_FILE);
+    ASSERT_TRUE(config != nullptr);
+
+    framework_t* fw = celix_frameworkFactory_createFramework(config);
+    ASSERT_TRUE(fw != nullptr);
+
+    auto* startedBundleIds = celix_framework_listBundles(fw);
+    auto* installedBundleIds = celix_framework_listInstalledBundles(fw);
+
+    /*
+     * 3 started: simple_test_bundle1, simple_test_bundle2 and 
simple_test_bundle3
+     */
+    EXPECT_EQ(celix_arrayList_size(startedBundleIds), 3);
+
+    /*
+     * 3 started: simple_test_bundle1, simple_test_bundle2 and 
simple_test_bundle3
+     * 2 installed: simple_test_bundle4 and simple_test_bundle5
+     */
+    EXPECT_EQ(celix_arrayList_size(installedBundleIds), 5);
+
+    celix_arrayList_destroy(startedBundleIds);
+    celix_arrayList_destroy(installedBundleIds);
+
+    framework_stop(fw);
+    framework_waitForStop(fw);
+    framework_destroy(fw);
+}
+
diff --git a/libs/framework/include/celix/BundleContext.h 
b/libs/framework/include/celix/BundleContext.h
index 66c79a0..ff5ee48 100644
--- a/libs/framework/include/celix/BundleContext.h
+++ b/libs/framework/include/celix/BundleContext.h
@@ -375,17 +375,22 @@ namespace celix {
 
         /**
          * @brief List the installed and started bundle ids.
-         * The bundle ids does not include the framework bundle (bundle id 
celix::FRAMEWORK_BUNDLE_ID).
+         * The bundle ids does not include the framework bundle (bundle id 
CELIX_FRAMEWORK_BUNDLE_ID).
+         *
+         * @return A vector with bundle ids.
          */
         [[nodiscard]] std::vector<long> listBundleIds() const {
-            std::vector<long> result{};
-            auto* ids = celix_bundleContext_listBundles(cCtx.get());
-            result.reserve(celix_arrayList_size(ids));
-            for (int i = 0 ; i < celix_arrayList_size(ids); ++i) {
-                result.push_back(celix_arrayList_getLong(ids, i));
-            }
-            celix_arrayList_destroy(ids);
-            return result;
+            return listBundlesInternal(true);
+        }
+
+        /**
+         * @brief List the installed bundle ids.
+         * The bundle ids does not include the framework bundle (bundle id 
CELIX_FRAMEWORK_BUNDLE_ID).
+         *
+         * @return A vector with bundle ids.
+         */
+        [[nodiscard]] std::vector<long> listInstalledBundleIds() {
+            return listBundlesInternal(false);
         }
 
         /**
@@ -600,6 +605,18 @@ namespace celix {
             }
          }
     private:
+        [[nodiscard]] std::vector<long> listBundlesInternal(bool activeOnly) 
const {
+            std::vector<long> result{};
+            auto* ids = activeOnly ?
+                        celix_bundleContext_listBundles(getCBundleContext()) :
+                        
celix_bundleContext_listInstalledBundles(getCBundleContext());
+            result.reserve(celix_arrayList_size(ids));
+            for (int i = 0; i < celix_arrayList_size(ids); ++i) {
+                result.push_back(celix_arrayList_getLong(ids, i));
+            }
+            celix_arrayList_destroy(ids);
+            return result;
+        }
 
         const std::shared_ptr<celix_bundle_context_t> cCtx;
         const std::shared_ptr<celix::dm::DependencyManager> dm;
diff --git a/libs/framework/include/celix/Constants.h 
b/libs/framework/include/celix/Constants.h
index 50e7939..2354222 100644
--- a/libs/framework/include/celix/Constants.h
+++ b/libs/framework/include/celix/Constants.h
@@ -180,6 +180,18 @@ namespace celix {
      */
     constexpr const char * const AUTO_START_6 = CELIX_AUTO_START_6;
 
+    /**
+     * @brief Celix framework environment property (named 
"CELIX_AUTO_INSTALL") which specified a (ordered) space
+     * separated set of bundles to install when the Celix framework is started.
+     *
+     * The Celix framework will first install and start bundles defined in the 
properties CELIX_AUTO_START_0 till
+     * CELIX_AUTO_START_6 and then install (ano not start!) the bundles listed 
in CELIX_AUTO_INSTALL.
+     *
+     * When the Celix framework stops the bundles are stopped in the reverse 
order. Started bundles in CELIX_AUTO_INSTALL
+     * are stopped first and of those bundles, the bundle mentioned last in a 
CELIX_AUTO_INSTALL set is stopped first.
+     * Then bundles defined in CELIX_AUTO_START_6 are stopped, followed by 
bundles defined in CELIX_AUTO_START_5, etc.
+     */
+    constexpr const char * const AUTO_INSTALL = CELIX_AUTO_INSTALL;
 
     /**
      * @brief Celix framework environment property (named 
"CELIX_BUNDLES_PATH") which specified a `;` separated
diff --git a/libs/framework/include/celix_bundle_context.h 
b/libs/framework/include/celix_bundle_context.h
index 80416d3..b9f55ae 100644
--- a/libs/framework/include/celix_bundle_context.h
+++ b/libs/framework/include/celix_bundle_context.h
@@ -834,12 +834,22 @@ size_t celix_bundleContext_useServicesWithOptions(
  * @brief List the installed and started bundle ids.
  * The bundle ids does not include the framework bundle (bundle id 
CELIX_FRAMEWORK_BUNDLE_ID).
  *
- * @param ctx The bundle context
+ * @param ctx The bundle context.
  * @return A array with bundle ids (long). The caller is responsible for 
destroying the array.
  */
 celix_array_list_t* celix_bundleContext_listBundles(celix_bundle_context_t 
*ctx);
 
 /**
+ * @brief List the installed bundle ids.
+ * The bundle ids does not include the framework bundle (bundle id 
CELIX_FRAMEWORK_BUNDLE_ID).
+ *
+ * @param ctx The bundle context.
+ * @return A array with bundle ids (long). The caller is responsible for 
destroying the array.
+ */
+celix_array_list_t* 
celix_bundleContext_listInstalledBundles(celix_bundle_context_t *ctx);
+
+
+/**
  * @brief Check whether a bundle is installed.
  * @param ctx       The bundle context.
  * @param bndId     The bundle id to check
diff --git a/libs/framework/include/celix_constants.h 
b/libs/framework/include/celix_constants.h
index 525187d..730f2b2 100644
--- a/libs/framework/include/celix_constants.h
+++ b/libs/framework/include/celix_constants.h
@@ -273,6 +273,19 @@ extern "C" {
  */
 #define CELIX_AUTO_START_6 "CELIX_AUTO_START_6"
 
+/**
+ * @brief Celix framework environment property (named "CELIX_AUTO_INSTALL") 
which specified a (ordered) space
+ * separated set of bundles to install when the Celix framework is started.
+ *
+ * The Celix framework will first install and start bundles defined in the 
properties CELIX_AUTO_START_0 till
+ * CELIX_AUTO_START_6 and then install (ano not start!) the bundles listed in 
CELIX_AUTO_INSTALL.
+ *
+ * When the Celix framework stops the bundles are stopped in the reverse 
order. Started bundles in CELIX_AUTO_INSTALL
+ * are stopped first and of those bundles, the bundle mentioned last in a 
CELIX_AUTO_INSTALL set is stopped first.
+ * Then bundles defined in CELIX_AUTO_START_6 are stopped, followed by bundles 
defined in CELIX_AUTO_START_5, etc.
+ */
+#define CELIX_AUTO_INSTALL "CELIX_AUTO_INSTALL"
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/libs/framework/include/celix_framework.h 
b/libs/framework/include/celix_framework.h
index 5758795..c819a71 100644
--- a/libs/framework/include/celix_framework.h
+++ b/libs/framework/include/celix_framework.h
@@ -24,6 +24,7 @@
 #include "celix_types.h"
 #include "celix_properties.h"
 #include "celix_log_level.h"
+#include "celix_array_list.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -182,6 +183,24 @@ void celix_framework_stopBundleAsync(celix_framework_t 
*fw, long bndId);
 void celix_framework_startBundleAsync(celix_framework_t *fw, long bndId);
 
 /**
+ * @brief List the installed and started bundle ids.
+ * The bundle ids does not include the framework bundle (bundle id 
CELIX_FRAMEWORK_BUNDLE_ID).
+ *
+ * @param framework The Celix framework.
+ * @return A array with bundle ids (long). The caller is responsible for 
destroying the array.
+ */
+celix_array_list_t* celix_framework_listBundles(celix_framework_t* framework);
+
+/**
+ * @brief List the installed bundle ids.
+ * The bundle ids does not include the framework bundle (bundle id 
CELIX_FRAMEWORK_BUNDLE_ID).
+ *
+ * @param framework The Celix framework.
+ * @return A array with bundle ids (long). The caller is responsible for 
destroying the array.
+ */
+celix_array_list_t* celix_framework_listInstalledBundles(celix_framework_t* 
framework);
+
+/**
  * @brief Wait until the framework event queue is empty.
  *
  * The Celix framework has an event queue which (among others) handles bundle 
events.
@@ -244,8 +263,6 @@ void celix_framework_waitForGenericEvent(celix_framework_t 
*fw, long eventId);
  */
 void celix_framework_waitForStop(celix_framework_t *framework);
 
-
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/libs/framework/src/bundle_context.c 
b/libs/framework/src/bundle_context.c
index 43b345b..08a96bf 100644
--- a/libs/framework/src/bundle_context.c
+++ b/libs/framework/src/bundle_context.c
@@ -1082,18 +1082,12 @@ long celix_bundleContext_installBundle(bundle_context_t 
*ctx, const char *bundle
     return celix_framework_installBundle(ctx->framework, bundleLoc, autoStart);
 }
 
-static void bundleContext_listBundlesCallback(void *handle, const bundle_t 
*c_bnd) {
-    celix_array_list_t* ids = handle;
-    long id = celix_bundle_getId(c_bnd);
-    if (id > 0) { //note skipping framework bundle id (0)
-        celix_arrayList_addLong(ids, id);
-    }
+celix_array_list_t* celix_bundleContext_listBundles(celix_bundle_context_t 
*ctx) {
+    return celix_framework_listBundles(ctx->framework);
 }
 
-celix_array_list_t* celix_bundleContext_listBundles(celix_bundle_context_t 
*ctx) {
-    celix_array_list_t *result = celix_arrayList_create();
-    celix_bundleContext_useBundles(ctx, result, 
bundleContext_listBundlesCallback);
-    return result;
+celix_array_list_t* 
celix_bundleContext_listInstalledBundles(celix_bundle_context_t *ctx) {
+    return celix_framework_listInstalledBundles(ctx->framework);
 }
 
 bool celix_bundleContext_isBundleInstalled(celix_bundle_context_t *ctx, long 
bndId) {
diff --git a/libs/framework/src/framework.c b/libs/framework/src/framework.c
index 9b5caa1..c2d139c 100644
--- a/libs/framework/src/framework.c
+++ b/libs/framework/src/framework.c
@@ -168,6 +168,7 @@ static celix_status_t frameworkActivator_stop(void * 
userData, bundle_context_t
 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 void celix_framework_addToEventQueue(celix_framework_t *fw, const 
celix_framework_event_t* event);
@@ -514,6 +515,7 @@ celix_status_t framework_start(framework_pt framework) {
     }
 
     framework_autoStartConfiguredBundles(framework);
+    framework_autoInstallConfiguredBundles(framework);
 
        if (status == CELIX_SUCCESS) {
         fw_log(framework->logger, CELIX_LOG_LEVEL_INFO, "Celix framework 
started");
@@ -542,6 +544,14 @@ static void 
framework_autoStartConfiguredBundles(celix_framework_t* fw) {
     celix_arrayList_destroy(installedBundles);
 }
 
+static void framework_autoInstallConfiguredBundles(celix_framework_t* fw) {
+    bundle_context_t *fwCtx = framework_getContext(fw);
+    const char* autoInstall = celix_bundleContext_getProperty(fwCtx, 
CELIX_AUTO_INSTALL, NULL);
+    if (autoInstall != NULL) {
+        framework_autoInstallConfiguredBundlesForList(fw, autoInstall, NULL);
+    }
+}
+
 
 static void framework_autoInstallConfiguredBundlesForList(celix_framework_t* 
fw, const char *autoStartIn, celix_array_list_t *installedBundles) {
     bundle_context_t *fwCtx = framework_getContext(fw);
@@ -556,7 +566,9 @@ static void 
framework_autoInstallConfiguredBundlesForList(celix_framework_t* fw,
             bundle_t *bnd = NULL;
             celix_status_t  rc = bundleContext_installBundle(fwCtx, location, 
&bnd);
             if (rc == CELIX_SUCCESS) {
-                celix_arrayList_add(installedBundles, bnd);
+                if (installedBundles != NULL) {
+                    celix_arrayList_add(installedBundles, bnd);
+                }
             } else {
                 printf("Could not install bundle '%s'\n", location);
             }
@@ -572,9 +584,13 @@ static void 
framework_autoStartConfiguredBundlesForList(celix_framework_t* fw, c
         long bndId = -1;
         bundle_t *bnd = celix_arrayList_get(installedBundles, i);
         bundle_getBundleId(bnd, &bndId);
-        bool started = celix_framework_startBundle(fw, bndId);
-        if (!started) {
-            fw_log(fw->logger, CELIX_LOG_LEVEL_ERROR, "Could not start bundle 
%s (bnd id = %li)\n", bnd->symbolicName, bndId);
+        if (celix_bundle_getState(bnd) != OSGI_FRAMEWORK_BUNDLE_ACTIVE) {
+            bool started = celix_framework_startBundle(fw, bndId);
+            if (!started) {
+                fw_log(fw->logger, CELIX_LOG_LEVEL_ERROR, "Could not start 
bundle %s (bnd id = %li)\n", bnd->symbolicName, bndId);
+            }
+        } 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);
         }
     }
 }
@@ -2595,6 +2611,32 @@ celix_status_t 
celix_framework_startBundleEntry(celix_framework_t* framework, ce
     return status;
 }
 
+static celix_array_list_t* 
celix_framework_listBundlesInternal(celix_framework_t* framework, bool 
activeOnly) {
+    celix_array_list_t* result = celix_arrayList_create();
+    celixThreadMutex_lock(&framework->dispatcher.mutex);
+    for (int i = 0; i < 
celix_arrayList_size(framework->installedBundles.entries); ++i) {
+        celix_framework_bundle_entry_t* entry = 
celix_arrayList_get(framework->installedBundles.entries, i);
+        if (entry->bndId == CELIX_FRAMEWORK_BUNDLE_ID) {
+            continue;
+        }
+        if (!activeOnly) {
+            celix_arrayList_addLong(result, entry->bndId);
+        } else if (celix_bundle_getState(entry->bnd) == 
OSGI_FRAMEWORK_BUNDLE_ACTIVE) {
+            celix_arrayList_addLong(result, entry->bndId);
+        }
+    }
+    celixThreadMutex_unlock(&framework->dispatcher.mutex);
+    return result;
+}
+
+celix_array_list_t* celix_framework_listBundles(celix_framework_t* framework) {
+    return celix_framework_listBundlesInternal(framework, true);
+}
+
+celix_array_list_t* celix_framework_listInstalledBundles(celix_framework_t* 
framework) {
+    return celix_framework_listBundlesInternal(framework, false);
+}
+
 void celix_framework_waitForEmptyEventQueue(celix_framework_t *fw) {
     assert(!celix_framework_isCurrentThreadTheEventLoop(fw));
 

Reply via email to