diff --git a/CHANGES.md b/CHANGES.md index 2720590a4..881cc237c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -33,7 +33,7 @@ limitations under the License. - pubsub_serializer.h is removed and no longer supported. Use pubsub_message_serialization_service.h instead. - C++11 support for dm is removed. C++14 is now the minimum required version. - C++17 string_view support is removed from the utils and framework lib. -- Apache Celix CMake bundle functions without a celix_ prefix or infix are removed. +- Apache Celix CMake container & bundle functions without a celix_ prefix or infix are removed. - Apache Celix CMake support for creating docker images and creating runtimes dirs is removed. - Support and usage of "service.lang" service property is removed. - Rename of `CELIX_FRAMEWORK_FRAMEWORK_CACHE_DIR` config property to `CELIX_FRAMEWORK_CACHE_DIR`. @@ -73,6 +73,10 @@ limitations under the License. to add service properties with the correct type. - Celix C++ Exception are now defined in the `celix/exceptions.h` header file. The `celix/Exception.h` and `celix/IOException.h` are removed. +- The seperator for `CELIX_AUTO_START_0` .. `CELIX_AUTO_START_6` and `CELIX_AUTO_INSTALL` is now a comma instead of a + space. +- The launcher now only has 2 public functions: `celix_launcher_launchAndWait` and `celix_launcher_triggerStop`. The + other functions are removed. ## New Features diff --git a/bundles/remote_services/remote_service_admin_dfi/gtest/client.properties.in b/bundles/remote_services/remote_service_admin_dfi/gtest/client.properties.in index 506ed25ea..76433350f 100644 --- a/bundles/remote_services/remote_service_admin_dfi/gtest/client.properties.in +++ b/bundles/remote_services/remote_service_admin_dfi/gtest/client.properties.in @@ -1,10 +1,11 @@ -CELIX_AUTO_START_1=@rsa_bundle_file@ @discovery_bundle_file@ @topology_manager_bundle_file@ @tst_bundle_file@ -LOGHELPER_ENABLE_STDOUT_FALLBACK=true -CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE=true -CELIX_FRAMEWORK_CACHE_DIR=.cacheClient - -DISCOVERY_CFG_POLL_INTERVAL=1 -DISCOVERY_CFG_POLL_TIMEOUT=5 -RSA_PORT=50881 -DISCOVERY_CFG_SERVER_PORT=50991 -DISCOVERY_CFG_POLL_ENDPOINTS=http://localhost:50992/org.apache.celix.discovery.configured \ No newline at end of file +{ + "CELIX_AUTO_START_1":"@rsa_bundle_file@,@discovery_bundle_file@,@topology_manager_bundle_file@,@tst_bundle_file@", + "LOGHELPER_ENABLE_STDOUT_FALLBACK":true, + "CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE":true, + "CELIX_FRAMEWORK_CACHE_DIR":".cacheClient", + "DISCOVERY_CFG_POLL_INTERVAL":1, + "DISCOVERY_CFG_POLL_TIMEOUT":5, + "RSA_PORT":50881, + "DISCOVERY_CFG_SERVER_PORT":50991, + "DISCOVERY_CFG_POLL_ENDPOINTS":"http://localhost:50992/org.apache.celix.discovery.configured" +} \ No newline at end of file diff --git a/bundles/remote_services/remote_service_admin_dfi/gtest/config.properties.in b/bundles/remote_services/remote_service_admin_dfi/gtest/config.properties.in index 52730b288..864e1cbdd 100644 --- a/bundles/remote_services/remote_service_admin_dfi/gtest/config.properties.in +++ b/bundles/remote_services/remote_service_admin_dfi/gtest/config.properties.in @@ -1,20 +1,5 @@ -# 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. - -CELIX_AUTO_START_1=@rsa_bundle_file@ @calc_bundle_file@ -LOGHELPER_ENABLE_STDOUT_FALLBACK=true -CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE=true +{ + "CELIX_AUTO_START_1":"@rsa_bundle_file@,@calc_bundle_file@", + "LOGHELPER_ENABLE_STDOUT_FALLBACK":true, + "CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE":true +} diff --git a/bundles/remote_services/remote_service_admin_dfi/gtest/server.properties.in b/bundles/remote_services/remote_service_admin_dfi/gtest/server.properties.in index 7812c7fe0..b15507049 100644 --- a/bundles/remote_services/remote_service_admin_dfi/gtest/server.properties.in +++ b/bundles/remote_services/remote_service_admin_dfi/gtest/server.properties.in @@ -1,26 +1,11 @@ -# 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. -CELIX_AUTO_START_1=@rsa_bundle_file@ @calc_bundle_file@ @remote_example_bundle_file@ @discovery_bundle_file@ @topology_manager_bundle_file@ -LOGHELPER_ENABLE_STDOUT_FALLBACK=true -CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE=true -CELIX_FRAMEWORK_CACHE_DIR=.cacheServer - -DISCOVERY_CFG_POLL_INTERVAL=1 -DISCOVERY_CFG_POLL_TIMEOUT=5 -RSA_PORT=50882 -DISCOVERY_CFG_SERVER_PORT=50992 -DISCOVERY_CFG_POLL_ENDPOINTS=http://localhost:50991/org.apache.celix.discovery.configured +{ + "CELIX_AUTO_START_1":"@rsa_bundle_file@,@calc_bundle_file@,@remote_example_bundle_file@,@discovery_bundle_file@,@topology_manager_bundle_file@", + "LOGHELPER_ENABLE_STDOUT_FALLBACK":true, + "CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE":true, + "CELIX_FRAMEWORK_CACHE_DIR":".cacheServer", + "DISCOVERY_CFG_POLL_INTERVAL":1, + "DISCOVERY_CFG_POLL_TIMEOUT":5, + "RSA_PORT":50882, + "DISCOVERY_CFG_SERVER_PORT":50992, + "DISCOVERY_CFG_POLL_ENDPOINTS":"http://localhost:50991/org.apache.celix.discovery.configured" +} diff --git a/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_client_server_tests.cc b/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_client_server_tests.cc index 7e903e1e9..e8fd6719a 100644 --- a/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_client_server_tests.cc +++ b/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_client_server_tests.cc @@ -44,16 +44,16 @@ typedef struct rsa_dfi_exception_test_service { int (*func1)(void *handle); }rsa_dfi_exception_test_service_t; - static celix_framework_t *serverFramework = NULL; - static celix_bundle_context_t *serverContext = NULL; + static celix_framework_t *serverFramework = nullptr; + static celix_bundle_context_t *serverContext = nullptr; - static celix_framework_t *clientFramework = NULL; - static celix_bundle_context_t *clientContext = NULL; + static celix_framework_t *clientFramework = nullptr; + static celix_bundle_context_t *clientContext = nullptr; - static rsa_dfi_exception_test_service_t *exceptionTestService = NULL; + static rsa_dfi_exception_test_service_t *exceptionTestService = nullptr; static long exceptionTestSvcId = -1L; - static remote_interceptor_t *serverSvcInterceptor=NULL; - static remote_interceptor_t *clientSvcInterceptor=NULL; + static remote_interceptor_t *serverSvcInterceptor=nullptr; + static remote_interceptor_t *clientSvcInterceptor=nullptr; static long serverSvcInterceptorSvcId = -1L; static long clientSvcInterceptorSvcId = -1L; static bool clientInterceptorPreProxyCallRetval=true; @@ -61,21 +61,23 @@ typedef struct rsa_dfi_exception_test_service { static void setupFm(bool useCurlShare) { //server - celix_properties_t *serverProps = celix_properties_load("server.properties"); - ASSERT_TRUE(serverProps != NULL); + celix_properties_t *serverProps = nullptr; + ASSERT_EQ(CELIX_SUCCESS, celix_properties_load("server.properties", 0, &serverProps)); + ASSERT_TRUE(serverProps != nullptr); serverFramework = celix_frameworkFactory_createFramework(serverProps); - ASSERT_TRUE(serverFramework != NULL); + ASSERT_TRUE(serverFramework != nullptr); serverContext = celix_framework_getFrameworkContext(serverFramework); - ASSERT_TRUE(serverContext != NULL); + ASSERT_TRUE(serverContext != nullptr); //client - celix_properties_t *clientProperties = celix_properties_load("client.properties"); + celix_properties_t *clientProperties = nullptr; + ASSERT_EQ(CELIX_SUCCESS, celix_properties_load("client.properties", 0, &clientProperties)); celix_properties_setBool(clientProperties, "RSA_DFI_USE_CURL_SHARE_HANDLE", useCurlShare); - ASSERT_TRUE(clientProperties != NULL); + ASSERT_TRUE(clientProperties != nullptr); clientFramework = celix_frameworkFactory_createFramework(clientProperties); - ASSERT_TRUE(clientFramework != NULL); + ASSERT_TRUE(clientFramework != nullptr); clientContext = celix_framework_getFrameworkContext(clientFramework); - ASSERT_TRUE(clientContext != NULL); + ASSERT_TRUE(clientContext != nullptr); } static void teardownFm(void) { @@ -92,7 +94,7 @@ typedef struct rsa_dfi_exception_test_service { celix_properties_set(properties, CELIX_RSA_SERVICE_EXPORTED_INTERFACES, RSA_DIF_EXCEPTION_TEST_SERVICE); celix_properties_set(properties, CELIX_RSA_SERVICE_EXPORTED_CONFIGS, "org.amdatu.remote.admin.http"); exceptionTestService = (rsa_dfi_exception_test_service_t *)calloc(1,sizeof(*exceptionTestService)); - exceptionTestService->handle = NULL; + exceptionTestService->handle = nullptr; exceptionTestService->func1 = rsaDfi_excepTestFunc1; exceptionTestSvcId = celix_bundleContext_registerService(serverContext, exceptionTestService, RSA_DIF_EXCEPTION_TEST_SERVICE, properties); } @@ -137,7 +139,7 @@ typedef struct rsa_dfi_exception_test_service { static void registerInterceptorService(void) { svcInterceptorPreExportCallRetval = true; serverSvcInterceptor = (remote_interceptor_t *)calloc(1,sizeof(*serverSvcInterceptor)); - serverSvcInterceptor->handle = NULL; + serverSvcInterceptor->handle = nullptr; serverSvcInterceptor->preProxyCall = serverServiceInterceptor_preProxyCall; serverSvcInterceptor->postProxyCall = serverServiceInterceptor_postProxyCall; serverSvcInterceptor->preExportCall = serverServiceInterceptor_preExportCall; @@ -153,7 +155,7 @@ typedef struct rsa_dfi_exception_test_service { clientInterceptorPreProxyCallRetval = true; clientSvcInterceptor = (remote_interceptor_t *)calloc(1,sizeof(*clientSvcInterceptor)); - clientSvcInterceptor->handle = NULL; + clientSvcInterceptor->handle = nullptr; clientSvcInterceptor->preProxyCall = clientServiceInterceptor_preProxyCall; clientSvcInterceptor->postProxyCall = clientServiceInterceptor_postProxyCall; clientSvcInterceptor->preExportCall = clientServiceInterceptor_preExportCall; @@ -472,8 +474,8 @@ class RsaDfiDynamicIpServerTestSuite : public ::testing::Test { char calcIdStr[32] = {0}; snprintf(calcIdStr, 32, "%li", calcId); - celix_array_list_t *svcRegistrations = NULL; - auto status = serverRsaSvc->exportService(serverRsaSvc->admin, calcIdStr, NULL, &svcRegistrations); + celix_array_list_t *svcRegistrations = nullptr; + auto status = serverRsaSvc->exportService(serverRsaSvc->admin, calcIdStr, nullptr, &svcRegistrations); ASSERT_EQ(CELIX_SUCCESS, status); ASSERT_EQ(1, celix_arrayList_size(svcRegistrations)); export_registration_t *exportedReg = static_cast(celix_arrayList_get(svcRegistrations, 0)); diff --git a/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_tests.cc b/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_tests.cc index 3195b4630..ad29905d8 100644 --- a/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_tests.cc +++ b/bundles/remote_services/remote_service_admin_dfi/gtest/src/rsa_tests.cc @@ -33,18 +33,19 @@ extern "C" { #define TST_CONFIGURATION_TYPE "org.amdatu.remote.admin.http" - static celix_framework_t *framework = NULL; - static celix_bundle_context_t *context = NULL; + static celix_framework_t *framework = nullptr; + static celix_bundle_context_t *context = nullptr; long calcSvcId = -1L; static void setupFm(void) { - celix_properties_t *fwProperties = celix_properties_load("config.properties"); - ASSERT_TRUE(fwProperties != NULL); + celix_properties_t *fwProperties = nullptr; + EXPECT_EQ(CELIX_SUCCESS, celix_properties_load("config.properties", 0, &fwProperties)); + ASSERT_TRUE(fwProperties != nullptr); framework = celix_frameworkFactory_createFramework(fwProperties); - ASSERT_TRUE(framework != NULL); + ASSERT_TRUE(framework != nullptr); context = celix_framework_getFrameworkContext(framework); - ASSERT_TRUE(context != NULL); + ASSERT_TRUE(context != nullptr); calcSvcId = celix_bundleContext_findService(context, CALCULATOR_SERVICE); @@ -87,8 +88,8 @@ extern "C" { char strSvcId[64]; snprintf(strSvcId, 64, "%li", calcSvcId); - celix_array_list_t *svcRegistration = NULL; - int rc = rsa->exportService(rsa->admin, strSvcId, NULL, &svcRegistration); + celix_array_list_t *svcRegistration = nullptr; + int rc = rsa->exportService(rsa->admin, strSvcId, nullptr, &svcRegistration); ASSERT_EQ(CELIX_SUCCESS, rc); ASSERT_EQ(1, celix_arrayList_size(svcRegistration)); @@ -155,7 +156,7 @@ extern "C" { } static void testBundles(void) { - celix_array_list_t* bundles = NULL; + celix_array_list_t* bundles = nullptr; int rc = bundleContext_getBundles(context, &bundles); ASSERT_EQ(0, rc); @@ -165,9 +166,9 @@ extern "C" { int size = arrayList_size(bundles); int i; for (i = 0; i < size; i += 1) { - celix_bundle_t *bundle = NULL; - module_pt module = NULL; - char *name = NULL; + celix_bundle_t *bundle = nullptr; + module_pt module = nullptr; + char *name = nullptr; bundle = (celix_bundle_t *) arrayList_get(bundles, i); bundle_getCurrentModule(bundle, &module); diff --git a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/gtest/src/RsaShmClientServerUnitTestSuite.cc b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/gtest/src/RsaShmClientServerUnitTestSuite.cc index 44ae8d99e..77ab646d5 100644 --- a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/gtest/src/RsaShmClientServerUnitTestSuite.cc +++ b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/gtest/src/RsaShmClientServerUnitTestSuite.cc @@ -35,6 +35,7 @@ #include "socket_ei.h" #include "stdio_ei.h" #include "pthread_ei.h" +#include "celix_properties_ei.h" #include "thpool_ei.h" #include "celix_errno.h" #include @@ -80,6 +81,7 @@ class RsaShmClientServerUnitTestSuite : public ::testing::Test { celix_ei_expect_pthread_cond_timedwait(nullptr, 1, 0); celix_ei_expect_thpool_init(nullptr, 0, nullptr); celix_ei_expect_thpool_add_work(nullptr, 0, 0); + celix_ei_expect_celix_properties_saveToStream(nullptr, 0, CELIX_SUCCESS); } @@ -139,6 +141,44 @@ TEST_F(RsaShmClientServerUnitTestSuite, SendMsg) { rsaShmServer_destroy(server); } +TEST_F(RsaShmClientServerUnitTestSuite, SendMsgErrorEncodePropertiesTest) { + //Given a rsa shm server + rsa_shm_server_t *server = nullptr; + auto status = rsaShmServer_create(ctx.get(), "shm_test_server", logHelper.get(), ReceiveMsgCallback, nullptr, &server); + EXPECT_EQ(CELIX_SUCCESS, status); + EXPECT_NE(nullptr, server); + + //And a rsa shm client + rsa_shm_client_manager_t *clientManager = nullptr; + status = rsaShmClientManager_create(ctx.get(), logHelper.get(), &clientManager); + EXPECT_EQ(CELIX_SUCCESS, status); + EXPECT_NE(nullptr, clientManager); + + // And the client is attached to the server + long serverId = 100;//dummy id + status = rsaShmClientManager_createOrAttachClient(clientManager, "shm_test_server", serverId); + EXPECT_EQ(CELIX_SUCCESS, status); + + //When an error is prepared for saveToStream + celix_ei_expect_celix_properties_saveToStream((void*)rsaShmClientManager_sendMsgTo, 0, ENOMEM); + + //And a message is sent + celix_autoptr(celix_properties_t) metadata = celix_properties_create(); + celix_properties_set(metadata, "CustomKey", "test"); + struct iovec request = {.iov_base = (void*)"request", .iov_len = strlen("request")}; + struct iovec response = {.iov_base = nullptr, .iov_len = 0}; + status = rsaShmClientManager_sendMsgTo(clientManager, "shm_test_server", serverId, metadata, &request, &response); + + //Then the injected error is returned + EXPECT_EQ(ENOMEM, status); + + rsaShmClientManager_destroyOrDetachClient(clientManager, "shm_test_server", serverId); + + rsaShmClientManager_destroy(clientManager); + + rsaShmServer_destroy(server); +} + TEST_F(RsaShmClientServerUnitTestSuite, SendMsgWithNoServer) { rsa_shm_client_manager_t *clientManager = nullptr; auto status = rsaShmClientManager_create(ctx.get(), logHelper.get(), &clientManager); diff --git a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_client.c b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_client.c index 7c236f7a8..70ffba0b7 100644 --- a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_client.c +++ b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_client.c @@ -278,8 +278,13 @@ celix_status_t rsaShmClientManager_sendMsgTo(rsa_shm_client_manager_t *clientMan return CELIX_ERROR_MAKE(CELIX_FACILITY_CERRNO, errno); } if (metadata != NULL) { - CELIX_PROPERTIES_ITERATE(metadata, iter) { - fprintf(fp,"%s=%s\n", iter.key, iter.entry.value); + status = celix_properties_saveToStream(metadata, fp, 0); + if (status != CELIX_SUCCESS) { + fclose(fp); + celix_logHelper_error( + clientManager->logHelper, "RsaShmClient: Error encoding metadata to memory stream. %d.", status); + celix_logHelper_logTssErrors(clientManager->logHelper, CELIX_LOG_LEVEL_ERROR); + return status; } } fclose(fp); diff --git a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_server.c b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_server.c index 4a8da5240..aaebbb368 100644 --- a/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_server.c +++ b/bundles/remote_services/remote_service_admin_shm_v2/rsa_shm/src/rsa_shm_server.c @@ -167,7 +167,7 @@ static void rsaShmServer_terminateMsgHandling(rsa_shm_msg_control_t *ctrl) { static void rsaShmServer_msgHandlingWork(void *data) { assert(data != NULL); - int status = CELIX_SUCCESS; + int status = CELIX_SUCCESS; struct rsa_shm_server_thpool_work_data *workData = data; rsa_shm_server_t *server = workData->server; assert(server != NULL); @@ -179,9 +179,9 @@ static void rsaShmServer_msgHandlingWork(void *data) { celix_properties_t *metadataProps = NULL; if (workData->metadataSize != 0) { - metadataProps = celix_properties_loadFromString(metaDataString); - if (metadataProps == NULL) { + if (celix_properties_loadFromString(metaDataString, 0, &metadataProps) != CELIX_SUCCESS) { celix_logHelper_warning(server->loghelper, "RsaShmServer: Parse metadata failed."); + celix_logHelper_logTssErrors(server->loghelper, CELIX_LOG_LEVEL_WARNING); } } diff --git a/bundles/remote_services/topology_manager/tms_tst/CMakeLists.txt b/bundles/remote_services/topology_manager/tms_tst/CMakeLists.txt index dfb913135..e28d81295 100644 --- a/bundles/remote_services/topology_manager/tms_tst/CMakeLists.txt +++ b/bundles/remote_services/topology_manager/tms_tst/CMakeLists.txt @@ -54,19 +54,21 @@ add_celix_bundle_dependencies(test_tm_scoped Celix::rsa_dfi Celix::rsa_topology_ file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/config.properties" - CONTENT " -CELIX_AUTO_START_1=$ $ $ $ -LOGHELPER_ENABLE_STDOUT_FALLBACK=true -CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE=true -") + CONTENT "{ + \"CELIX_AUTO_START_1\":\"$,$,$,$\", + \"LOGHELPER_ENABLE_STDOUT_FALLBACK\":true, + \"CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE\":true, + \"CELIX_FRAMEWORK_CACHE_DIR\":\".rstm_cache\" +}") file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/config_import.properties" - CONTENT " -CELIX_AUTO_START_1=$ $ $ $ -LOGHELPER_ENABLE_STDOUT_FALLBACK=true -CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE=true -") + CONTENT "{ + \"CELIX_AUTO_START_1\":\"$,$,$,$\", + \"LOGHELPER_ENABLE_STDOUT_FALLBACK\":true, + \"CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE\":true, + \"CELIX_FRAMEWORK_CACHE_DIR\":\".rstm_import_cache\" +}") configure_file("scope.json" "scope.json") configure_file("scope2.json" "scope2.json") diff --git a/bundles/remote_services/topology_manager/tms_tst/tms_tests.cpp b/bundles/remote_services/topology_manager/tms_tst/tms_tests.cpp index 009f77af7..235afb20c 100644 --- a/bundles/remote_services/topology_manager/tms_tst/tms_tests.cpp +++ b/bundles/remote_services/topology_manager/tms_tst/tms_tests.cpp @@ -19,10 +19,12 @@ #include "gtest/gtest.h" -#include -#include +#include +#include #include "celix_bundle_context.h" +#include "celix_framework_factory.h" +#include "celix_version.h" extern "C" { @@ -57,34 +59,36 @@ extern "C" { #define TST_CONFIGURATION_TYPE "org.amdatu.remote.admin.http" - static framework_pt framework = NULL; - static celix_bundle_context_t *context = NULL; + static framework_pt framework = nullptr; + static celix_bundle_context_t *context = nullptr; - static service_reference_pt scopeServiceRef = NULL; - static tm_scope_service_pt tmScopeService = NULL; + static service_reference_pt scopeServiceRef = nullptr; + static tm_scope_service_pt tmScopeService = nullptr; - static service_reference_pt calcRef = NULL; - static calculator_service_t *calc = NULL; + static service_reference_pt calcRef = nullptr; + static calculator_service_t *calc = nullptr; - static service_reference_pt rsaRef = NULL; - static remote_service_admin_service_t *rsa = NULL; + static service_reference_pt rsaRef = nullptr; + static remote_service_admin_service_t *rsa = nullptr; - static service_reference_pt discRef = NULL; - static disc_mock_service_t *discMock = NULL; + static service_reference_pt discRef = nullptr; + static disc_mock_service_t *discMock = nullptr; - static service_reference_pt testRef = NULL; - static tst_service_t *testImport = NULL; + static service_reference_pt testRef = nullptr; + static tst_service_t *testImport = nullptr; - static service_reference_pt eplRef = NULL; - static endpoint_listener_t *eplService = NULL; // actually this is the topology manager + static service_reference_pt eplRef = nullptr; + static endpoint_listener_t *eplService = nullptr; // actually this is the topology manager - static void setupFm(void) { - int rc = 0; - rc = celixLauncher_launch("config.properties", &framework); - EXPECT_EQ(CELIX_SUCCESS, rc); + static void setupFm() { + celix_properties_t* config; + ASSERT_EQ(CELIX_SUCCESS, celix_properties_load("config.properties", 0, &config)); - celix_bundle_t *bundle = NULL; - rc = framework_getFrameworkBundle(framework, &bundle); + framework = celix_frameworkFactory_createFramework(config); + ASSERT_NE(nullptr, framework); + + celix_bundle_t *bundle = nullptr; + celix_status_t rc = framework_getFrameworkBundle(framework, &bundle); EXPECT_EQ(CELIX_SUCCESS, rc); rc = bundle_getContext(bundle, &context); @@ -92,28 +96,28 @@ extern "C" { rc = bundleContext_getServiceReference(context, (char *)CELIX_RSA_REMOTE_SERVICE_ADMIN, &rsaRef); EXPECT_EQ(CELIX_SUCCESS, rc); - EXPECT_TRUE(rsaRef != NULL); + EXPECT_TRUE(rsaRef != nullptr); rc = bundleContext_getService(context, rsaRef, (void **)&rsa); EXPECT_EQ(CELIX_SUCCESS, rc); rc = bundleContext_getServiceReference(context, (char *)TOPOLOGYMANAGER_SCOPE_SERVICE, &scopeServiceRef); EXPECT_EQ(CELIX_SUCCESS, rc); - EXPECT_TRUE(scopeServiceRef != NULL); + EXPECT_TRUE(scopeServiceRef != nullptr); rc = bundleContext_getService(context, scopeServiceRef, (void **)&tmScopeService); EXPECT_EQ(CELIX_SUCCESS, rc); rc = bundleContext_getServiceReference(context, (char *)CALCULATOR_SERVICE, &calcRef); EXPECT_EQ(CELIX_SUCCESS, rc); - EXPECT_TRUE(calcRef != NULL); + EXPECT_TRUE(calcRef != nullptr); rc = bundleContext_getService(context, calcRef, (void **)&calc); EXPECT_EQ(CELIX_SUCCESS, rc); rc = bundleContext_getServiceReference(context, (char *)DISC_MOCK_SERVICE_NAME, &discRef); EXPECT_EQ(CELIX_SUCCESS, rc); - EXPECT_TRUE(discRef != NULL); + EXPECT_TRUE(discRef != nullptr); rc = bundleContext_getService(context, discRef, (void **)&discMock); EXPECT_EQ(CELIX_SUCCESS, rc); @@ -121,61 +125,61 @@ extern "C" { printf("==> Finished setup.\n"); } - static void teardownFm(void) { + static void teardownFm() { printf("==> Starting teardown.\n"); int rc = 0; - rc = bundleContext_ungetService(context, scopeServiceRef, NULL); + rc = bundleContext_ungetService(context, scopeServiceRef, nullptr); EXPECT_EQ(CELIX_SUCCESS, rc); rc = bundleContext_ungetServiceReference(context,scopeServiceRef); EXPECT_EQ(CELIX_SUCCESS, rc); - rc = bundleContext_ungetService(context, calcRef, NULL); + rc = bundleContext_ungetService(context, calcRef, nullptr); EXPECT_EQ(CELIX_SUCCESS, rc); rc = bundleContext_ungetServiceReference(context,calcRef); EXPECT_EQ(CELIX_SUCCESS, rc); - rc = bundleContext_ungetService(context, rsaRef, NULL); + rc = bundleContext_ungetService(context, rsaRef, nullptr); EXPECT_EQ(CELIX_SUCCESS, rc); rc = bundleContext_ungetServiceReference(context,rsaRef); EXPECT_EQ(CELIX_SUCCESS, rc); - rc = bundleContext_ungetService(context, discRef, NULL); + rc = bundleContext_ungetService(context, discRef, nullptr); EXPECT_EQ(CELIX_SUCCESS, rc); rc = bundleContext_ungetServiceReference(context,discRef); EXPECT_EQ(CELIX_SUCCESS, rc); - celixLauncher_stop(framework); - celixLauncher_waitForShutdown(framework); - celixLauncher_destroy(framework); + celix_frameworkFactory_destroyFramework(framework); - scopeServiceRef = NULL; - tmScopeService = NULL; - calcRef = NULL; - calc = NULL; + scopeServiceRef = nullptr; + tmScopeService = nullptr; + calcRef = nullptr; + calc = nullptr; - rsaRef = NULL; - rsa = NULL; - discRef = NULL; - discMock = NULL; + rsaRef = nullptr; + rsa = nullptr; + discRef = nullptr; + discMock = nullptr; - testRef = NULL; - testImport = NULL; + testRef = nullptr; + testImport = nullptr; - eplRef = NULL; - eplService = NULL; + eplRef = nullptr; + eplService = nullptr; - context = NULL; - framework = NULL; + context = nullptr; + framework = nullptr; } - static void setupFmImport(void) { - int rc = 0; - rc = celixLauncher_launch("config_import.properties", &framework); - EXPECT_EQ(CELIX_SUCCESS, rc); + static void setupFmImport() { + celix_properties_t* config; + ASSERT_EQ(CELIX_SUCCESS, celix_properties_load("config_import.properties", 0, &config)); + + framework = celix_frameworkFactory_createFramework(config); + ASSERT_NE(nullptr, framework); - celix_bundle_t *bundle = NULL; - rc = framework_getFrameworkBundle(framework, &bundle); + celix_bundle_t *bundle = nullptr; + celix_status_t rc = framework_getFrameworkBundle(framework, &bundle); EXPECT_EQ(CELIX_SUCCESS, rc); rc = bundle_getContext(bundle, &context); @@ -187,78 +191,76 @@ extern "C" { rc = bundleContext_getServiceReference(context, (char *)CELIX_RSA_REMOTE_SERVICE_ADMIN, &rsaRef); EXPECT_EQ(CELIX_SUCCESS, rc); - EXPECT_TRUE(rsaRef != NULL); + EXPECT_TRUE(rsaRef != nullptr); rc = bundleContext_getService(context, rsaRef, (void **)&rsa); EXPECT_EQ(CELIX_SUCCESS, rc); rc = bundleContext_getServiceReference(context, (char *)TOPOLOGYMANAGER_SCOPE_SERVICE, &scopeServiceRef); EXPECT_EQ(CELIX_SUCCESS, rc); - EXPECT_TRUE(scopeServiceRef != NULL); + EXPECT_TRUE(scopeServiceRef != nullptr); rc = bundleContext_getService(context, scopeServiceRef, (void **)&tmScopeService); EXPECT_EQ(CELIX_SUCCESS, rc); rc = bundleContext_getServiceReference(context, (char *)TST_SERVICE_NAME, &testRef); EXPECT_EQ(CELIX_SUCCESS, rc); - EXPECT_TRUE(testRef != NULL); + EXPECT_TRUE(testRef != nullptr); rc = bundleContext_getService(context, testRef, (void **)&testImport); EXPECT_EQ(CELIX_SUCCESS, rc); rc = bundleContext_getServiceReference(context, (char*) CELIX_RSA_ENDPOINT_LISTENER_SERVICE_NAME, &eplRef); EXPECT_EQ(CELIX_SUCCESS, rc); - EXPECT_TRUE(eplRef != NULL); + EXPECT_TRUE(eplRef != nullptr); rc = bundleContext_getService(context, eplRef, (void **)&eplService); EXPECT_EQ(CELIX_SUCCESS, rc); } - static void teardownFmImport(void) { + static void teardownFmImport() { int rc = 0; - rc = bundleContext_ungetService(context, rsaRef, NULL); + rc = bundleContext_ungetService(context, rsaRef, nullptr); EXPECT_EQ(CELIX_SUCCESS, rc); rc = bundleContext_ungetServiceReference(context,rsaRef); EXPECT_EQ(CELIX_SUCCESS, rc); - rc = bundleContext_ungetService(context, scopeServiceRef, NULL); + rc = bundleContext_ungetService(context, scopeServiceRef, nullptr); EXPECT_EQ(CELIX_SUCCESS, rc); rc = bundleContext_ungetServiceReference(context,scopeServiceRef); EXPECT_EQ(CELIX_SUCCESS, rc); - rc = bundleContext_ungetService(context, testRef, NULL); + rc = bundleContext_ungetService(context, testRef, nullptr); EXPECT_EQ(CELIX_SUCCESS, rc); rc = bundleContext_ungetServiceReference(context,testRef); EXPECT_EQ(CELIX_SUCCESS, rc); - rc = bundleContext_ungetService(context, eplRef, NULL); + rc = bundleContext_ungetService(context, eplRef, nullptr); EXPECT_EQ(CELIX_SUCCESS, rc); rc = bundleContext_ungetServiceReference(context,eplRef); EXPECT_EQ(CELIX_SUCCESS, rc); - celixLauncher_stop(framework); - celixLauncher_waitForShutdown(framework); - celixLauncher_destroy(framework); + celix_frameworkFactory_destroyFramework(framework); - scopeServiceRef = NULL; - tmScopeService = NULL; - calcRef = NULL; - calc = NULL; + scopeServiceRef = nullptr; + tmScopeService = nullptr; + calcRef = nullptr; + calc = nullptr; - rsaRef = NULL; - rsa = NULL; - discRef = NULL; - discMock = NULL; + rsaRef = nullptr; + rsa = nullptr; + discRef = nullptr; + discMock = nullptr; - testRef = NULL; - testImport = NULL; + testRef = nullptr; + testImport = nullptr; - eplRef = NULL; - eplService = NULL; + eplRef = nullptr; + eplService = nullptr; - context = NULL; - framework = NULL; + context = nullptr; + framework = nullptr; } /// \TEST_CASE_ID{1} @@ -267,7 +269,7 @@ extern "C" { /// \TEST_CASE_DESC Checks if 3 bundles are installed after the framework setup static void testBundles(void) { printf("Begin: %s\n", __func__); - celix_array_list_t* bundles = NULL; + celix_array_list_t* bundles = nullptr; int rc = bundleContext_getBundles(context, &bundles); EXPECT_EQ(0, rc); @@ -277,9 +279,9 @@ extern "C" { int size = arrayList_size(bundles); int i; for (i = 0; i < size; i += 1) { - celix_bundle_t *bundle = NULL; - module_pt module = NULL; - char *name = NULL; + celix_bundle_t *bundle = nullptr; + module_pt module = nullptr; + char *name = nullptr; bundle = (celix_bundle_t *) arrayList_get(bundles, i); bundle_getCurrentModule(bundle, &module); @@ -304,11 +306,11 @@ extern "C" { *nr_imported = 0; js_root = json_load_file(fileName, 0, &error); - if (js_root != NULL) { + if (js_root != nullptr) { json_t *js_exportServices = json_object_get(js_root, JSON_EXPORT_SERVICES); json_t *js_importServices = json_object_get(js_root, JSON_IMPORT_SERVICES); - if (js_exportServices != NULL) { + if (js_exportServices != nullptr) { if (json_is_array(js_exportServices)) { int i = 0; int size = json_array_size(js_exportServices); @@ -323,15 +325,15 @@ extern "C" { json_t* js_key2 = json_object_get(js_service, JSON_SERVICE_KEY2); properties = celix_properties_create(); - if (js_serviceZone != NULL) { + if (js_serviceZone != nullptr) { celix_properties_set(properties, (char*)JSON_SERVICE_ZONE, (char*)json_string_value(js_serviceZone)); } - if (js_key1 != NULL) { + if (js_key1 != nullptr) { celix_properties_set(properties, (char*)JSON_SERVICE_KEY1, (char*)json_string_value(js_key1)); } - if (js_key2 != NULL) { + if (js_key2 != nullptr) { celix_properties_set(properties, (char*)JSON_SERVICE_KEY2, (char*)json_string_value(js_key2)); } @@ -345,7 +347,7 @@ extern "C" { } } - if (js_importServices != NULL) { + if (js_importServices != nullptr) { if (json_is_array(js_importServices)) { int i = 0; int size = json_array_size(js_importServices); @@ -475,7 +477,7 @@ extern "C" { EXPECT_EQ(0, nr_imported); int rc = 0; - endpoint_description_t *endpoint = NULL; + endpoint_description_t *endpoint = nullptr; celix_properties_t *props = celix_properties_create(); celix_properties_set(props, CELIX_RSA_ENDPOINT_SERVICE_ID, "42"); @@ -483,13 +485,14 @@ extern "C" { celix_properties_set(props, CELIX_RSA_ENDPOINT_ID, "eec5404d-51d0-47ef-8d86-c825a8beda42-42"); celix_properties_set(props, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, TST_CONFIGURATION_TYPE); celix_properties_set(props, CELIX_FRAMEWORK_SERVICE_NAME, "org.apache.celix.test.MyBundle"); - celix_properties_set(props, "service.version", "1.0.0"); + auto* v = celix_version_create(1, 0, 0, nullptr); + celix_properties_assignVersion(props, "service.version", v); celix_properties_set(props, "zone", "a_zone"); rc = endpointDescription_create(props, &endpoint); EXPECT_EQ(CELIX_SUCCESS, rc); - rc = eplService->endpointAdded(eplService->handle, endpoint, NULL); + rc = eplService->endpointAdded(eplService->handle, endpoint, nullptr); EXPECT_EQ(CELIX_SUCCESS, rc); celix_framework_waitForEmptyEventQueue(framework); @@ -502,7 +505,7 @@ extern "C" { usleep(1000); } while (!imported && iteration++ < 1000); - rc = eplService->endpointRemoved(eplService->handle, endpoint, NULL); + rc = eplService->endpointRemoved(eplService->handle, endpoint, nullptr); EXPECT_EQ(CELIX_SUCCESS, rc); celix_framework_waitForEmptyEventQueue(framework); @@ -527,7 +530,7 @@ extern "C" { EXPECT_EQ(1, nr_imported); int rc = 0; - endpoint_description_t *endpoint = NULL; + endpoint_description_t *endpoint = nullptr; celix_properties_t *props = celix_properties_create(); celix_properties_set(props, CELIX_RSA_ENDPOINT_SERVICE_ID, "42"); @@ -535,13 +538,14 @@ extern "C" { celix_properties_set(props, CELIX_RSA_ENDPOINT_ID, "eec5404d-51d0-47ef-8d86-c825a8beda42-42"); celix_properties_set(props, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, TST_CONFIGURATION_TYPE); celix_properties_set(props, CELIX_FRAMEWORK_SERVICE_NAME, "org.apache.celix.test.MyBundle"); - celix_properties_set(props, "service.version", "1.0.0"); + auto* v = celix_version_create(1, 0, 0, nullptr); + celix_properties_assignVersion(props, "service.version", v); celix_properties_set(props, "zone", "a_zone"); rc = endpointDescription_create(props, &endpoint); EXPECT_EQ(CELIX_SUCCESS, rc); - rc = eplService->endpointAdded(eplService->handle, endpoint, NULL); + rc = eplService->endpointAdded(eplService->handle, endpoint, nullptr); EXPECT_EQ(CELIX_SUCCESS, rc); celix_framework_waitForEmptyEventQueue(framework); @@ -554,7 +558,7 @@ extern "C" { usleep(1000); } while (!imported && iteration++ < 1000); - rc = eplService->endpointRemoved(eplService->handle, endpoint, NULL); + rc = eplService->endpointRemoved(eplService->handle, endpoint, nullptr); EXPECT_EQ(CELIX_SUCCESS, rc); celix_framework_waitForEmptyEventQueue(framework); @@ -578,7 +582,7 @@ extern "C" { EXPECT_EQ(1, nr_imported); int rc = 0; - endpoint_description_t *endpoint = NULL; + endpoint_description_t *endpoint = nullptr; celix_properties_t *props = celix_properties_create(); celix_properties_set(props, CELIX_RSA_ENDPOINT_SERVICE_ID, "42"); @@ -586,13 +590,14 @@ extern "C" { celix_properties_set(props, CELIX_RSA_ENDPOINT_ID, "eec5404d-51d0-47ef-8d86-c825a8beda42-42"); celix_properties_set(props, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, TST_CONFIGURATION_TYPE); celix_properties_set(props, CELIX_FRAMEWORK_SERVICE_NAME, "org.apache.celix.test.MyBundle"); - celix_properties_set(props, "service.version", "1.0.0"); //TODO find out standard in osgi spec + auto*v = celix_version_create(1, 0, 0, nullptr); + celix_properties_assignVersion(props, "service.version", v); celix_properties_set(props, "zone", "a_zone"); rc = endpointDescription_create(props, &endpoint); EXPECT_EQ(CELIX_SUCCESS, rc); - rc = eplService->endpointAdded(eplService->handle, endpoint, NULL); + rc = eplService->endpointAdded(eplService->handle, endpoint, nullptr); EXPECT_EQ(CELIX_SUCCESS, rc); celix_framework_waitForEmptyEventQueue(framework); @@ -600,7 +605,7 @@ extern "C" { bool imported = testImport->IsImported(testImport); EXPECT_EQ(false, imported); - rc = eplService->endpointRemoved(eplService->handle, endpoint, NULL); + rc = eplService->endpointRemoved(eplService->handle, endpoint, nullptr); EXPECT_EQ(CELIX_SUCCESS, rc); celix_framework_waitForEmptyEventQueue(framework); @@ -624,7 +629,7 @@ extern "C" { EXPECT_EQ(2, nr_imported); int rc = 0; - endpoint_description_t *endpoint = NULL; + endpoint_description_t *endpoint = nullptr; celix_properties_t *props = celix_properties_create(); celix_properties_set(props, CELIX_RSA_ENDPOINT_SERVICE_ID, "42"); @@ -632,13 +637,14 @@ extern "C" { celix_properties_set(props, CELIX_RSA_ENDPOINT_ID, "eec5404d-51d0-47ef-8d86-c825a8beda42-42"); celix_properties_set(props, CELIX_RSA_SERVICE_IMPORTED_CONFIGS, TST_CONFIGURATION_TYPE); celix_properties_set(props, CELIX_FRAMEWORK_SERVICE_NAME, "org.apache.celix.test.MyBundle"); - celix_properties_set(props, "service.version", "1.0.0"); + auto*v = celix_version_create(1, 0, 0, nullptr); + celix_properties_assignVersion(props, "service.version", v); celix_properties_set(props, "zone", "a_zone"); rc = endpointDescription_create(props, &endpoint); EXPECT_EQ(CELIX_SUCCESS, rc); - rc = eplService->endpointAdded(eplService->handle, endpoint, NULL); + rc = eplService->endpointAdded(eplService->handle, endpoint, nullptr); EXPECT_EQ(CELIX_SUCCESS, rc); celix_framework_waitForEmptyEventQueue(framework); @@ -653,7 +659,7 @@ extern "C" { EXPECT_EQ(true, imported); - rc = eplService->endpointRemoved(eplService->handle, endpoint, NULL); + rc = eplService->endpointRemoved(eplService->handle, endpoint, nullptr); EXPECT_EQ(CELIX_SUCCESS, rc); celix_framework_waitForEmptyEventQueue(framework); diff --git a/cmake/cmake_celix/BundlePackaging.cmake b/cmake/cmake_celix/BundlePackaging.cmake index 112d942f4..0bdf0f654 100644 --- a/cmake/cmake_celix/BundlePackaging.cmake +++ b/cmake/cmake_celix/BundlePackaging.cmake @@ -31,13 +31,13 @@ endif () find_program(JAR_COMMAND jar NO_CMAKE_FIND_ROOT_PATH) if (JAR_COMMAND AND NOT CELIX_USE_ZIP_INSTEAD_OF_JAR) - message(STATUS "Using jar to create bundles") + message(DEBUG "Using jar to create bundles") else () find_program(ZIP_COMMAND zip NO_CMAKE_FIND_ROOT_PATH) if (ZIP_COMMAND) - message(STATUS "Using zip to create bundles") + message(DEBUG "Using zip to create bundles") else () - message(FATAL_ERROR "A jar or zip command is needed to jar/zip bundles") + message(FATAL_ERROR "A jar or zip command is needed to created bundles") endif () endif () @@ -48,7 +48,7 @@ if (NOT TARGET celix-bundles) endif () ##### -macro(extract_version_parts VERSION MAJOR MINOR PATCH) +macro(_extract_version_parts VERSION MAJOR MINOR PATCH) set(MAJOR "0") set(MINOR "0") set(PATCH "0") @@ -67,20 +67,20 @@ macro(extract_version_parts VERSION MAJOR MINOR PATCH) endif () endmacro() -function(set_library_version TARGET VERSION) +function(celix_set_library_version TARGET VERSION) if (VERSION AND TARGET) - extract_version_parts("${VERSION}" MAJOR MINOR PATCH) + _extract_version_parts("${VERSION}" MAJOR MINOR PATCH) #NOTE setting aligning ABI version with major part of the interface version. #This is simpeler than using the :: approach of libtool set_property(TARGET ${TARGET} PROPERTY VERSION "${VERSION}") set_property(TARGET ${TARGET} PROPERTY SOVERSION ${MAJOR}) else () - message(WARNING "set_library_version: Cannot set version info TARGET and/or VERSION not provided") + message(WARNING "celix_set_library_version: Cannot set version info TARGET and/or VERSION not provided") endif () endfunction() -function(check_lib LIB) +function(_check_lib LIB) if (TARGET ${LIB}) #ok elseif (IS_ABSOLUTE ${LIB} AND EXISTS ${LIB}) @@ -90,7 +90,7 @@ function(check_lib LIB) endif () endfunction() -function(check_bundle BUNDLE) +function(_check_bundle BUNDLE) if (TARGET ${BUNDLE}) get_target_property(BUNDLE_FILE ${BUNDLE} "BUNDLE_FILE") if (NOT BUNDLE_FILE) @@ -191,7 +191,7 @@ function(add_celix_bundle) message(FATAL_ERROR "add_bundle function requires a value for SOURCES or ACTIVATOR not both") endif () if (BUNDLE_ACTIVATOR) - check_lib(${BUNDLE_ACTIVATOR}) + _check_lib(${BUNDLE_ACTIVATOR}) endif () if (NOT DEFINED BUNDLE_GROUP) set(BUNDLE_GROUP "") @@ -246,7 +246,7 @@ function(add_celix_bundle) if (BUNDLE_SOURCES) #create lib from sources add_library(${BUNDLE_TARGET_NAME} SHARED ${BUNDLE_SOURCES}) - set_library_version(${BUNDLE_TARGET_NAME} ${BUNDLE_VERSION}) + celix_set_library_version(${BUNDLE_TARGET_NAME} ${BUNDLE_VERSION}) set_target_properties(${BUNDLE_TARGET_NAME} PROPERTIES "BUNDLE_TARGET_IS_LIB" TRUE "BUNDLE_TARGET" "${BUNDLE_TARGET_NAME}_bundle" @@ -451,7 +451,7 @@ function(celix_bundle_libs) list(REMOVE_AT ARGN 0) #check if arg 0 is corrent - check_bundle(${BUNDLE}) + _check_bundle(${BUNDLE}) get_target_property(BUNDLE_DIR ${BUNDLE} "BUNDLE_CONTENT_DIR") get_target_property(BUNDLE_GEN_DIR ${BUNDLE} "BUNDLE_GEN_DIR") @@ -536,7 +536,7 @@ function(celix_bundle_import_libs) list(REMOVE_AT ARGN 0) #check if arg 0 is correct - check_bundle(${BUNDLE}) + _check_bundle(${BUNDLE}) get_target_property(LIBS ${BUNDLE} "BUNDLE_IMPORT_LIBS") diff --git a/cmake/cmake_celix/ContainerPackaging.cmake b/cmake/cmake_celix/ContainerPackaging.cmake index 78e799eb9..71c8c3c19 100644 --- a/cmake/cmake_celix/ContainerPackaging.cmake +++ b/cmake/cmake_celix/ContainerPackaging.cmake @@ -18,7 +18,7 @@ set(CELIX_DEFAULT_CONTAINER_CXX_OPTION ON CACHE BOOL "Whether the default container options is CXX. If OFF this will be C") -##### setup bundles/container target +# Setup bundles/container target if (NOT TARGET celix-containers) add_custom_target(celix-containers ALL DEPENDS $ @@ -30,12 +30,8 @@ if (NOT TARGET celix-containers) list(APPEND CLEANFILES "${CMAKE_BINARY_DIR}/celix") set_directory_properties(PROPERTIES ADDITIONAL_CLEAN_FILES "${CLEANFILES}") endif () -##### -function(add_deploy) - message(DEPRECATION "deploy_bundles_dir is depecrated, use celix_container_bundles_dir instead.") - add_celix_container(${ARGN}) -endfunction() + #[[ Add a Celix container, consisting out of a selection of bundles and a Celix launcher. @@ -221,23 +217,27 @@ function(add_celix_container) file(GENERATE OUTPUT "${STAGE1_LAUNCHER_SRC}" CONTENT "#include + +#define CELIX_MULTI_LINE_STRING(...) #__VA_ARGS__ + int main(int argc, char *argv[]) { - const char * config = \"\\ -CELIX_CONTAINER_NAME=$\\n\\ -CELIX_BUNDLES_PATH=bundles\\n\\ -$<$>:CELIX_AUTO_START_0=$, >\\n>\\ -$<$>:CELIX_AUTO_START_1=$, >\\n>\\ -$<$>:CELIX_AUTO_START_2=$, >\\n>\\ -$<$>:CELIX_AUTO_START_3=$, >\\n>\\ -$<$>:CELIX_AUTO_START_4=$, >\\n>\\ -$<$>:CELIX_AUTO_START_5=$, >\\n>\\ -$<$>:CELIX_AUTO_START_6=$, >\\n>\\ -$<$>:CELIX_AUTO_INSTALL=$, >\\n>\\ -$,\\n\\ ->\"; - - celix_properties_t *embeddedProps = celix_properties_loadFromString(config); - return celixLauncher_launchAndWaitForShutdown(argc, argv, embeddedProps); + const char * config = CELIX_MULTI_LINE_STRING( +{ + $<$>:\"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\":\"$,$>\"$> + $<$>:\"CELIX_AUTO_INSTALL\":\"$,$>\"$> + $,$ + >$<$>:$> + \"CELIX_BUNDLES_PATH\":\"bundles\"$ + \"CELIX_CONTAINER_NAME\":\"$\" +}); + + return celix_launcher_launchAndWait(argc, argv, config); } " ) @@ -270,18 +270,20 @@ $,\\n\ if (CONTAINER_USE_CONFIG) file(GENERATE OUTPUT "${STAGE1_PROPERTIES}" - CONTENT "CELIX_CONTAINER_NAME=$ -CELIX_BUNDLES_PATH=bundles -$<$>: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=$, >> -$<$>:CELIX_AUTO_INSTALL=$, >> -$, ->" + CONTENT "{ + $<$>:\"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\":\"$,$>\"$> + $<$>:\"CELIX_AUTO_INSTALL\":\"$,$>\"$> + $,$ + >$<$>:$> + \"CELIX_BUNDLES_PATH\":\"bundles\"$ + \"CELIX_CONTAINER_NAME\":\"$\" +}" ) file(GENERATE OUTPUT "${CONTAINER_PROPS}" @@ -290,9 +292,10 @@ $, else () file(GENERATE OUTPUT "${STAGE1_PROPERTIES}" - CONTENT "$, -> -" + CONTENT "{ + $,$ + > +}" ) #Condition is there so that config.properties file will only be generated if there are runtime properties file(GENERATE @@ -367,13 +370,6 @@ $, set_directory_properties(PROPERTIES ADDITIONAL_CLEAN_FILES "${CLEANFILES}") endfunction() - -#NOTE can be used for drivers/proxies/endpoints bundle dirs -function(deploy_bundles_dir) - message(DEPRECATION "deploy_bundles_dir is depecrated, use celix_container_bundles_dir instead.") - celix_container_bundles_dir(${ARGN}) -endfunction() - #[[ Copy the specified bundles to a specified dir in the container build dir. @@ -456,11 +452,6 @@ function(celix_container_bundles_dir) endforeach() endfunction() -function(deploy_bundles) - message(DEPRECATION "deploy_bundles is depecrated, use celix_container_bundles instead.") - celix_container_bundles(${ARGN}) -endfunction() - #[[ Add a selection of bundles to the Celix container. @@ -565,6 +556,7 @@ function(celix_container_bundles) endif () endforeach() + list(REMOVE_DUPLICATES 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 @@ -602,8 +594,36 @@ function(_celix_container_check_duplicate_bundles) endforeach() endfunction() -function(deploy_properties) - celix_container_runtime_properties(${ARGN}) +#[[ +Internal function that converts a property string to a JSON field entry. +The result is stored in the OUTPUT_VAR_NAME variable. + +In the key the char `=` is not allowed and should be escaped as `\=` (in CMake this is `\\=`, because \ is already an +escape char in CMake). +In the value the char `=` is allowed. + +To handle \= string sequences the \= entries are replaced with a placeholder (____) and after the +split the placeholder is replaced with =. + +```CMake +_celix_convert_property_to_json("prop1=val1" OUTPUT_VAR_NAME) # OUTPUT_VAR_NAME will be set to "\"prop1\":\"val1\"" +_celix_convert_property_to_json("prop1=va=l1" OUTPUT_VAR_NAME) # OUTPUT_VAR_NAME will be set to "\"prop1\":\"va=l1\"" +_celix_convert_property_to_json("prop\\=1=val1" OUTPUT_VAR_NAME) # OUTPUT_VAR_NAME will be set to "\"prop=1\":\"val1\"" +``` +]] +function(_celix_convert_property_to_json INPUT_STR OUTPUT_VAR_NAME) + set(PLACEHOLDER "____") + string(REPLACE "\\=" "${PLACEHOLDER}" TEMP_INPUT_STR "${INPUT_STR}") + + string(REGEX MATCH "([^=]+)=(.*)" _ ${TEMP_INPUT_STR}) + set(KEY ${CMAKE_MATCH_1}) + set(VALUE ${CMAKE_MATCH_2}) + + #Replace replaced \= and \\ with = and \ + string(REPLACE "${PLACEHOLDER}" "=" KEY "${KEY}") + string(REPLACE "${PLACEHOLDER}" "=" VALUE "${VALUE}") + + set(${OUTPUT_VAR_NAME} "\"${KEY}\":\"${VALUE}\"" PARENT_SCOPE) endfunction() #[[ @@ -627,17 +647,13 @@ function(celix_container_runtime_properties) get_target_property(PROPS ${CONTAINER_TARGET} "CONTAINER_RUNTIME_PROPERTIES") foreach(PROP IN ITEMS ${ARGN}) + _celix_convert_property_to_json(${PROP} PROP) list(APPEND PROPS ${PROP}) endforeach() set_target_properties(${CONTAINER_TARGET} PROPERTIES "CONTAINER_RUNTIME_PROPERTIES" "${PROPS}") endfunction() -function(deploy_embedded_properties) - message(DEPRECATION "deploy_embedded_properties is depecrated, use celix_container_embedded_properties instead.") - celix_container_embedded_properties(${ARGN}) -endfunction() - #[[ Add the provided properties to the target Celix container config properties. These properties will be embedded into the generated Celix launcher. @@ -659,6 +675,7 @@ function(celix_container_embedded_properties) get_target_property(PROPS ${CONTAINER_TARGET} "CONTAINER_EMBEDDED_PROPERTIES") foreach(PROP IN ITEMS ${ARGN}) + _celix_convert_property_to_json(${PROP} PROP) list(APPEND PROPS ${PROP}) endforeach() diff --git a/documents/containers.md b/documents/containers.md index 77e673e89..a48754dd2 100644 --- a/documents/containers.md +++ b/documents/containers.md @@ -45,13 +45,22 @@ will create the following main source file (note: reformatted for display purpos ```C++ //${CMAKE_BINARY_DIR}/celix/gen/containers/my_empty_container/main.cc #include +#include +#define CELIX_MULTI_LINE_STRING(...) #__VA_ARGS__ int main(int argc, char *argv[]) { - const char * config = "\ -CELIX_CONTAINER_NAME=my_empty_container\n\ -CELIX_BUNDLES_PATH=bundles\n\ -"; - celix_properties_t *embeddedProps = celix_properties_loadFromString(config); - return celixLauncher_launchAndWaitForShutdown(argc, argv, embeddedProps); + const char * config = CELIX_MULTI_LINE_STRING( +{ + "CELIX_BUNDLES_PATH":"bundles", + "CELIX_CONTAINER_NAME":"my_empty_container" +}); + + celix_properties_t *embeddedProps; + celix_status_t status = celix_properties_loadFromString(config, 0, &embeddedProps); + if (status != CELIX_SUCCESS) { + celix_err_printErrors(stderr, "Error creating embedded properties.", NULL); + return -1; + } + return celix_launcher_launch(argc, argv, embeddedProps); } ``` @@ -84,16 +93,25 @@ add_celix_container(my_web_shell_container will create the following main source file (note: reformatted for display purpose): ```C++ #include +#include +#define CELIX_MULTI_LINE_STRING(...) #__VA_ARGS__ int main(int argc, char *argv[]) { - const char * config = "\ -CELIX_CONTAINER_NAME=my_web_shell_container\n\ -CELIX_BUNDLES_PATH=bundles\n\ -CELIX_AUTO_START_3=celix_http_admin-Debug.zip celix_shell-Debug.zip celix_shell_wui-Debug.zip\n\ -CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL=debug\n\ -CELIX_HTTP_ADMIN_LISTENING_PORTS=8888"; - - celix_properties_t *embeddedProps = celix_properties_loadFromString(config); - return celixLauncher_launchAndWaitForShutdown(argc, argv, embeddedProps); + const char * config = CELIX_MULTI_LINE_STRING( +{ + "CELIX_AUTO_START_3":"celix_http_admin-Debug.zip celix_shell-Debug.zip celix_shell_wui-Debug.zip", + "CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL":"debug", + "CELIX_HTTP_ADMIN_LISTENING_PORTS":"8888", + "CELIX_BUNDLES_PATH":"bundles", + "CELIX_CONTAINER_NAME":"my_web_shell_container" +}); + + celix_properties_t *embeddedProps; + celix_status_t status = celix_properties_loadFromString(config, 0, &embeddedProps); + if (status != CELIX_SUCCESS) { + celix_err_printErrors(stderr, "Error creating embedded properties.", NULL); + return -1; + } + return celix_launcher_launch(argc, argv, embeddedProps); } ``` diff --git a/documents/framework.md b/documents/framework.md index 6825adb53..d18535a56 100644 --- a/documents/framework.md +++ b/documents/framework.md @@ -109,7 +109,7 @@ The Apache Celix launcher also does some additional work: //src/launcher.c #include int main(int argc, char** argv) { - return celixLauncher_launchAndWaitForShutdown(argc, argv, NULL); + return celix_launcher_launchAndWait(argc, argv, NULL); } ``` ```cmake @@ -191,7 +191,7 @@ int main() { //src/launcher.c #include int main(int argc, char** argv) { - return celixLauncher_launchAndWaitForShutdown(argc, argv, NULL); + return celix_launcher_launch(argc, argv, NULL); } ``` diff --git a/documents/properties_encoding.md b/documents/properties_encoding.md index c4cdb38d7..29078de25 100644 --- a/documents/properties_encoding.md +++ b/documents/properties_encoding.md @@ -255,7 +255,7 @@ Properties encoding flags can be used control the behavior of the encoding. The ## Properties Decoding JSON can be decoded to an Apache Celix properties object using -the `celix_properties_load2`, `celix_properties_loadFromStream` and `celix_properties_loadFromString2` functions. These +the `celix_properties_load`, `celix_properties_loadFromStream` and `celix_properties_loadFromString` functions. These functions take a JSON input and decode it to a properties object. Because properties use a flat key structure, decoding a nested JSON object to properties results in combining JSON object keys to a flat key structure. This can result in key collisions. @@ -290,7 +290,7 @@ Combined with the following code: int main() { celix_autoptr(celix_properties_t) props; - celix_status_t status = celix_properties_load2("example.json", 0, &props): + celix_status_t status = celix_properties_load("example.json", 0, &props): (void)status; //for production code check status CELIX_PROPERTIES_ITERATE(props, iter) { printf("key=%s, value=%s\n", celix_properties_key(iter.key), celix_properties_value(iter.entry.value)); diff --git a/examples/celix-examples/bundle_with_private_lib/CMakeLists.txt b/examples/celix-examples/bundle_with_private_lib/CMakeLists.txt index ab963418b..8c839f504 100644 --- a/examples/celix-examples/bundle_with_private_lib/CMakeLists.txt +++ b/examples/celix-examples/bundle_with_private_lib/CMakeLists.txt @@ -19,7 +19,7 @@ add_library(tlib SHARED tlib/src/test.c ) target_include_directories(tlib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/tlib/include) -set_library_version(tlib "4.3.2") # sets target propery VERSION to 4.3.2 and SOVERSION to 4 +celix_set_library_version(tlib "4.3.2") # sets target propery VERSION to 4.3.2 and SOVERSION to 4 add_celix_bundle(hellotest VERSION "1.2" diff --git a/examples/celix-examples/hello_world_c/CMakeLists.txt b/examples/celix-examples/hello_world_c/CMakeLists.txt index de275ead0..1ae721f5d 100644 --- a/examples/celix-examples/hello_world_c/CMakeLists.txt +++ b/examples/celix-examples/hello_world_c/CMakeLists.txt @@ -21,9 +21,10 @@ add_celix_bundle(hello_world_c ) add_celix_container(hello_world_c_container + C GROUP c_examples BUNDLES Celix::shell Celix::shell_tui hello_world_c -) \ No newline at end of file +) diff --git a/libs/framework/gtest/CMakeLists.txt b/libs/framework/gtest/CMakeLists.txt index 9eca0896b..a6184dada 100644 --- a/libs/framework/gtest/CMakeLists.txt +++ b/libs/framework/gtest/CMakeLists.txt @@ -20,6 +20,8 @@ celix_bundle_name(simple_test_bundle1 "Simple Test Bundle") celix_bundle_group(simple_test_bundle1 "test/group") celix_bundle_description(simple_test_bundle1 "Test Description") +add_celix_bundle(dup_symbolic_name_bundle NO_ACTIVATOR VERSION 1.0.0 SYMBOLIC_NAME simple_test_bundle1) + add_celix_bundle(simple_test_bundle2 NO_ACTIVATOR VERSION 1.0.0) add_celix_bundle(simple_test_bundle3 NO_ACTIVATOR VERSION 1.0.0) add_celix_bundle(bundle_with_exception SOURCES src/nop_activator.c VERSION 1.0.0) @@ -80,11 +82,12 @@ add_celix_bundle_dependencies(test_framework simple_test_bundle2 simple_test_bundle3 simple_test_bundle4 simple_test_bundle5 bundle_with_exception bundle_with_bad_export unresolvable_bundle simple_cxx_bundle simple_cxx_dep_man_bundle cmp_test_bundle - celix_err_test_bundle) + celix_err_test_bundle dup_symbolic_name_bundle) target_include_directories(test_framework PRIVATE ../src) celix_deprecated_utils_headers(test_framework) celix_get_bundle_file(simple_test_bundle1 SIMPLE_TEST_BUNDLE1) +celix_get_bundle_file(dup_symbolic_name_bundle DUP_SYMBOLIC_NAME_BUNDLE) 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) @@ -104,6 +107,7 @@ celix_get_bundle_file(cond_test_bundle COND_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(empty.properties.in empty.properties @ONLY) configure_file(install_and_start_bundles.properties.in install_and_start_bundles.properties @ONLY) celix_target_bundle_set_definition(test_framework NAME CELIX_ERR_TEST_BUNDLE celix_err_test_bundle) @@ -114,6 +118,7 @@ target_compile_definitions(test_framework PRIVATE SIMPLE_TEST_BUNDLE3_LOCATION="${SIMPLE_TEST_BUNDLE3}" SIMPLE_TEST_BUNDLE4_LOCATION="${SIMPLE_TEST_BUNDLE4_FILENAME}" SIMPLE_TEST_BUNDLE5_LOCATION="${SIMPLE_TEST_BUNDLE5_FILENAME}" + DUP_SYMBOLIC_NAME_BUNDLE_LOCATION="${DUP_SYMBOLIC_NAME_BUNDLE}" TEST_BUNDLE_WITH_EXCEPTION_LOCATION="${BUNDLE_WITH_EXCEPTION}" BUNDLE_WITH_BAD_EXPORT_LOCATION="${BUNDLE_WITH_BAD_EXPORT}" TEST_BUNDLE_UNRESOLVABLE_LOCATION="${UNRESOLVABLE_BUNDLE}" @@ -140,6 +145,7 @@ if (EI_TESTS) src/FrameworkBundleWithErrorInjectionTestSuite.cc src/FrameworkFactoryWithErrorInjectionTestSuite.cc src/ManifestErrorInjectionTestSuite.cc + src/CelixLauncherErrorInjectionTestSuite.cc ) target_compile_definitions(test_framework_with_ei PRIVATE SIMPLE_TEST_BUNDLE1_LOCATION="${SIMPLE_TEST_BUNDLE1}" diff --git a/libs/framework/gtest/config.properties.in b/libs/framework/gtest/config.properties.in index f5931a4a5..f594096d2 100644 --- a/libs/framework/gtest/config.properties.in +++ b/libs/framework/gtest/config.properties.in @@ -1,19 +1,4 @@ -# 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. - -LOGHELPER_ENABLE_STDOUT_FALLBACK=true -CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE=true \ No newline at end of file +{ + "LOGHELPER_ENABLE_STDOUT_FALLBACK":true, + "CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE":true +} diff --git a/libs/framework/gtest/empty.properties.in b/libs/framework/gtest/empty.properties.in new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/libs/framework/gtest/empty.properties.in @@ -0,0 +1 @@ +{} diff --git a/libs/framework/gtest/framework1.properties.in b/libs/framework/gtest/framework1.properties.in index 567d19732..1d72fbbd7 100644 --- a/libs/framework/gtest/framework1.properties.in +++ b/libs/framework/gtest/framework1.properties.in @@ -1,20 +1,5 @@ -# 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. - -CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE=true -CELIX_FRAMEWORK_FRAMEWORK_CACHE_DIR=.cacheFramework1 -LOGHELPER_ENABLE_STDOUT_FALLBACK=true +{ + "CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE":true, + "CELIX_FRAMEWORK_FRAMEWORK_CACHE_DIR":".cacheFramework1", + "LOGHELPER_ENABLE_STDOUT_FALLBACK":true +} diff --git a/libs/framework/gtest/framework2.properties.in b/libs/framework/gtest/framework2.properties.in index 234b7a20e..d9ff4738e 100644 --- a/libs/framework/gtest/framework2.properties.in +++ b/libs/framework/gtest/framework2.properties.in @@ -1,20 +1,5 @@ -# 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. - -CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE=true -CELIX_FRAMEWORK_FRAMEWORK_CACHE_DIR=.cacheFramework2 -LOGHELPER_ENABLE_STDOUT_FALLBACK=true +{ + "CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE":true, + "CELIX_FRAMEWORK_FRAMEWORK_CACHE_DIR":".cacheFramework2", + "LOGHELPER_ENABLE_STDOUT_FALLBACK":true +} diff --git a/libs/framework/gtest/install_and_start_bundles.properties.in b/libs/framework/gtest/install_and_start_bundles.properties.in index d51721efe..b730adb94 100644 --- a/libs/framework/gtest/install_and_start_bundles.properties.in +++ b/libs/framework/gtest/install_and_start_bundles.properties.in @@ -1,29 +1,8 @@ -# 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. - -CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE=true - -#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 +{ + "CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE":true, + "CELIX_AUTO_START_1":"@SIMPLE_TEST_BUNDLE1@,@SIMPLE_TEST_BUNDLE2@,Invalid1.zip", + "CELIX_AUTO_START_3":"@SIMPLE_TEST_BUNDLE2@,@SIMPLE_TEST_BUNDLE3@,Invalid2.zip", + "CELIX_AUTO_INSTALL":"@SIMPLE_TEST_BUNDLE3@,@SIMPLE_TEST_BUNDLE4@,@SIMPLE_TEST_BUNDLE5@,Invalid3.zip" +} diff --git a/libs/framework/gtest/src/BundleArchiveWithErrorInjectionTestSuite.cc b/libs/framework/gtest/src/BundleArchiveWithErrorInjectionTestSuite.cc index 03100ddff..47819d81e 100644 --- a/libs/framework/gtest/src/BundleArchiveWithErrorInjectionTestSuite.cc +++ b/libs/framework/gtest/src/BundleArchiveWithErrorInjectionTestSuite.cc @@ -57,6 +57,7 @@ class BundleArchiveWithErrorInjectionTestSuite : public ::testing::Test { void teardownErrorInjectors() { celix_ei_expect_celix_properties_create(nullptr, 0, nullptr); + celix_ei_expect_celix_properties_save(nullptr, 0, CELIX_SUCCESS); celix_ei_expect_asprintf(nullptr, 0, 0); celix_ei_expect_calloc(nullptr, 0, nullptr); celix_ei_expect_malloc(nullptr, 0, nullptr); @@ -209,7 +210,7 @@ TEST_F(CelixBundleArchiveErrorInjectionTestSuite, ArchiveCreateErrorTest) { EXPECT_EQ(CELIX_SUCCESS, celix_utils_extractZipFile(SIMPLE_TEST_BUNDLE1_LOCATION, testExtractDir, nullptr)); EXPECT_EQ(CELIX_SUCCESS, celix_bundleArchive_create(&fw, TEST_ARCHIVE_ROOT, 2, testExtractDir, &archive)); - bundleArchive_destroy(archive); + celix_bundleArchive_destroy(archive); archive = nullptr; std::this_thread::sleep_for(std::chrono::milliseconds(10)); celix_utils_touch(SIMPLE_TEST_BUNDLE1_LOCATION); @@ -222,7 +223,7 @@ TEST_F(CelixBundleArchiveErrorInjectionTestSuite, ArchiveCreateErrorTest) { EXPECT_EQ(CELIX_SUCCESS, celix_bundleArchive_create(&fw, TEST_ARCHIVE_ROOT, 1, SIMPLE_TEST_BUNDLE1_LOCATION, &archive)); - bundleArchive_destroy(archive); + celix_bundleArchive_destroy(archive); archive = nullptr; std::this_thread::sleep_for(std::chrono::milliseconds(10)); celix_utils_touch(SIMPLE_TEST_BUNDLE1_LOCATION); @@ -257,4 +258,19 @@ TEST_F(CelixBundleArchiveErrorInjectionTestSuite, ArchiveCreateErrorTest) { teardownErrorInjectors(); EXPECT_EQ(CELIX_SUCCESS, celix_bundleCache_destroy(cache)); -} \ No newline at end of file +} + +TEST_F(CelixBundleArchiveErrorInjectionTestSuite, StoreBundleStatePropertiesErrorTest) { + // Given a framework + auto fw = celix::createFramework({ + {CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE, "true"}, + }); + auto ctx = fw->getFrameworkBundleContext(); + + // When an error is prepped for celix_properties_save + celix_ei_expect_celix_properties_save((void*)celix_bundleArchive_create, 1, CELIX_FILE_IO_EXCEPTION); + + // When the bundle install, a bundle id is returned (async bundle install) + long bndId = ctx->installBundle(SIMPLE_TEST_BUNDLE1_LOCATION); + EXPECT_LT(bndId, 0); +} diff --git a/libs/framework/gtest/src/CelixBundleCacheErrorInjectionTestSuite.cc b/libs/framework/gtest/src/CelixBundleCacheErrorInjectionTestSuite.cc index 2082013e4..9745da35f 100644 --- a/libs/framework/gtest/src/CelixBundleCacheErrorInjectionTestSuite.cc +++ b/libs/framework/gtest/src/CelixBundleCacheErrorInjectionTestSuite.cc @@ -21,6 +21,7 @@ #include +#include "celix/FrameworkFactory.h" #include "celix_bundle_cache.h" #include "celix_constants.h" #include "celix_file_utils.h" @@ -28,6 +29,7 @@ #include "celix_log.h" #include "celix_properties.h" #include "celix_utils_ei.h" +#include "celix_properties_ei.h" #include "asprintf_ei.h" #include "bundle_archive_private.h" @@ -54,6 +56,7 @@ class CelixBundleCacheErrorInjectionTestSuite : public ::testing::Test { celix_ei_expect_celix_stringHashMap_create(nullptr, 0, nullptr); celix_ei_expect_malloc(nullptr, 0, nullptr); celix_ei_expect_calloc(nullptr, 0, nullptr); + celix_ei_expect_celix_properties_load(nullptr, 0, CELIX_SUCCESS); celix_frameworkLogger_destroy(fw.logger); celix_properties_destroy(fw.configurationMap); } @@ -107,13 +110,18 @@ TEST_F(CelixBundleCacheErrorInjectionTestSuite, ArchiveCreateErrorTest) { celix_ei_expect_celix_utils_writeOrCreateString((void*)celix_bundleCache_createArchive, 0, nullptr); EXPECT_EQ(CELIX_ENOMEM, celix_bundleCache_createArchive(cache, 1, SIMPLE_TEST_BUNDLE1_LOCATION, &archive)); EXPECT_EQ(nullptr, archive); - EXPECT_EQ(-1, celix_bundleCache_findBundleIdForLocation(cache, SIMPLE_TEST_BUNDLE1_LOCATION)); + long bndId; + auto status = celix_bundleCache_findBundleIdForLocation(cache, SIMPLE_TEST_BUNDLE1_LOCATION, &bndId); + EXPECT_EQ(CELIX_SUCCESS, status); + EXPECT_EQ(-1, bndId); EXPECT_FALSE(celix_bundleCache_isBundleIdAlreadyUsed(cache, 1)); celix_ei_expect_calloc((void*)celix_bundleArchive_create, 0, nullptr); EXPECT_EQ(CELIX_ENOMEM, celix_bundleCache_createArchive(cache, 1, SIMPLE_TEST_BUNDLE1_LOCATION, &archive)); EXPECT_EQ(nullptr, archive); - EXPECT_EQ(-1, celix_bundleCache_findBundleIdForLocation(cache, SIMPLE_TEST_BUNDLE1_LOCATION)); + status = celix_bundleCache_findBundleIdForLocation(cache, SIMPLE_TEST_BUNDLE1_LOCATION, &bndId); + EXPECT_EQ(CELIX_SUCCESS, status); + EXPECT_EQ(-1, bndId); EXPECT_FALSE(celix_bundleCache_isBundleIdAlreadyUsed(cache, 1)); EXPECT_EQ(CELIX_SUCCESS, celix_bundleCache_destroy(cache)); @@ -163,4 +171,35 @@ TEST_F(CelixBundleCacheErrorInjectionTestSuite, CreateBundleArchivesCacheErrorTe celix_ei_expect_celix_utils_writeOrCreateString((void*)celix_bundleCache_createArchive, 0, nullptr); EXPECT_EQ(CELIX_ENOMEM, celix_bundleCache_createBundleArchivesCache(&fw, true)); EXPECT_EQ(CELIX_SUCCESS, celix_bundleCache_destroy(cache)); -} \ No newline at end of file +} + +TEST_F(CelixBundleCacheErrorInjectionTestSuite, LoadBundleStatePropertiesErrorTest) { + // Given a celix framework + auto fw = celix::createFramework( + {{"CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL", "trace"}, {CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE, "true"}}); + auto ctx = fw->getFrameworkBundleContext(); + + // And an installed bundle (with a bundle cache) + long bndId = ctx->installBundle(SIMPLE_TEST_BUNDLE1_LOCATION); + EXPECT_GT(bndId, -1); + + // When framework is stopped + ctx.reset(); + fw.reset(); + + // And a new framework is created + fw = celix::createFramework( + {{"CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL", "trace"}, {CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE, "false"}}); + ctx = fw->getFrameworkBundleContext(); + + // When the bundle is uninstalled + celix_bundleContext_uninstallBundle(ctx->getCBundleContext(), bndId); + + // And a celix_properties_load error is injected + celix_ei_expect_celix_properties_load( + (void*)celix_bundleCache_findBundleIdForLocation, 1, CELIX_FILE_IO_EXCEPTION); + + // Then installing the bundle will fail + bndId = ctx->installBundle(SIMPLE_TEST_BUNDLE1_LOCATION); + EXPECT_EQ(bndId, -1); //async install, so bundle id is returned +} diff --git a/libs/framework/gtest/src/CelixBundleCacheTestSuite.cc b/libs/framework/gtest/src/CelixBundleCacheTestSuite.cc index 42e397c53..a9393adfd 100644 --- a/libs/framework/gtest/src/CelixBundleCacheTestSuite.cc +++ b/libs/framework/gtest/src/CelixBundleCacheTestSuite.cc @@ -54,13 +54,18 @@ TEST_F(CelixBundleCacheTestSuite, ArchiveCreateDestroyTest) { auto location = celix_bundleArchive_getLocation(archive); EXPECT_STREQ(SIMPLE_TEST_BUNDLE1_LOCATION, location); free(location); - EXPECT_EQ(1, celix_bundleCache_findBundleIdForLocation(fw.cache, SIMPLE_TEST_BUNDLE1_LOCATION)); + long bndId; + auto status = celix_bundleCache_findBundleIdForLocation(fw.cache, SIMPLE_TEST_BUNDLE1_LOCATION, &bndId); + EXPECT_EQ(CELIX_SUCCESS, status); + EXPECT_EQ(1, bndId); EXPECT_TRUE(celix_bundleCache_isBundleIdAlreadyUsed(fw.cache, 1)); std::string loc = celix_bundleArchive_getPersistentStoreRoot(archive); EXPECT_TRUE(celix_utils_directoryExists(loc.c_str())); celix_bundleArchive_invalidate(archive); celix_bundleCache_destroyArchive(fw.cache, archive); - EXPECT_EQ(-1, celix_bundleCache_findBundleIdForLocation(fw.cache, SIMPLE_TEST_BUNDLE1_LOCATION)); + status = celix_bundleCache_findBundleIdForLocation(fw.cache, SIMPLE_TEST_BUNDLE1_LOCATION, &bndId); + EXPECT_EQ(CELIX_SUCCESS, status); + EXPECT_EQ(-1, bndId); EXPECT_FALSE(celix_bundleCache_isBundleIdAlreadyUsed(fw.cache, 1)); EXPECT_FALSE(celix_utils_directoryExists(loc.c_str())); } @@ -72,7 +77,10 @@ TEST_F(CelixBundleCacheTestSuite, NonPermanentDestroyTest) { std::string loc = celix_bundleArchive_getPersistentStoreRoot(archive); EXPECT_TRUE(celix_utils_directoryExists(loc.c_str())); celix_bundleCache_destroyArchive(fw.cache, archive); - EXPECT_EQ(1, celix_bundleCache_findBundleIdForLocation(fw.cache, SIMPLE_TEST_BUNDLE1_LOCATION)); + long bndId; + auto status = celix_bundleCache_findBundleIdForLocation(fw.cache, SIMPLE_TEST_BUNDLE1_LOCATION, &bndId); + EXPECT_EQ(CELIX_SUCCESS, status); + EXPECT_EQ(1, bndId); EXPECT_TRUE(celix_bundleCache_isBundleIdAlreadyUsed(fw.cache, 1)); EXPECT_TRUE(celix_utils_directoryExists(loc.c_str())); } @@ -94,8 +102,13 @@ TEST_F(CelixBundleCacheTestSuite, CreateBundleArchivesCacheTest) { celix_properties_set(fw.configurationMap, CELIX_AUTO_START_1, SIMPLE_TEST_BUNDLE1_LOCATION); celix_properties_set(fw.configurationMap, CELIX_AUTO_INSTALL, SIMPLE_TEST_BUNDLE2_LOCATION); EXPECT_EQ(CELIX_SUCCESS, celix_bundleCache_createBundleArchivesCache(&fw, true)); - EXPECT_EQ(1, celix_bundleCache_findBundleIdForLocation(fw.cache, SIMPLE_TEST_BUNDLE1_LOCATION)); + long bndId; + auto status = celix_bundleCache_findBundleIdForLocation(fw.cache, SIMPLE_TEST_BUNDLE1_LOCATION, &bndId); + EXPECT_EQ(CELIX_SUCCESS, status); + EXPECT_EQ(1, bndId); EXPECT_TRUE(celix_bundleCache_isBundleIdAlreadyUsed(fw.cache, 1)); - EXPECT_EQ(2, celix_bundleCache_findBundleIdForLocation(fw.cache, SIMPLE_TEST_BUNDLE2_LOCATION)); + status = celix_bundleCache_findBundleIdForLocation(fw.cache, SIMPLE_TEST_BUNDLE2_LOCATION, &bndId); + EXPECT_EQ(CELIX_SUCCESS, status); + EXPECT_EQ(2, bndId); EXPECT_TRUE(celix_bundleCache_isBundleIdAlreadyUsed(fw.cache, 2)); } \ No newline at end of file diff --git a/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc b/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc index 01616065b..8a1c89336 100644 --- a/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc +++ b/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc @@ -47,6 +47,7 @@ class CelixBundleContextBundlesTestSuite : public ::testing::Test { 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_UNRESOLVABLE_LOC = "" TEST_BUNDLE_UNRESOLVABLE_LOCATION ""; + const char * const DUP_SYMBOLIC_NAME_BUNDLE_LOC = "" DUP_SYMBOLIC_NAME_BUNDLE_LOCATION ""; CelixBundleContextBundlesTestSuite() { properties = celix_properties_create(); @@ -79,6 +80,14 @@ TEST_F(CelixBundleContextBundlesTestSuite, InstallABundleTest) { ASSERT_TRUE(bndId >= 0); } +TEST_F(CelixBundleContextBundlesTestSuite, InstallBundleWithDuplicatedSymbolicNameTest) { + long bndId1 = celix_bundleContext_installBundle(ctx, TEST_BND1_LOC, true); + ASSERT_TRUE(bndId1 >= 0); + + long bndId2 = celix_bundleContext_installBundle(ctx, DUP_SYMBOLIC_NAME_BUNDLE_LOC, true); + ASSERT_TRUE(bndId2 < 0); +} + //TEST_F(CelixBundleContextBundlesTestSuite, InstallBundleWithBadExport) { // long bndId = celix_bundleContext_installBundle(ctx, BUNDLE_WITH_BAD_EXPORT_LOCATION, true); // ASSERT_TRUE(bndId >= 0); diff --git a/libs/framework/gtest/src/CelixFrameworkTestSuite.cc b/libs/framework/gtest/src/CelixFrameworkTestSuite.cc index 3eae055c6..7dc84bdb8 100644 --- a/libs/framework/gtest/src/CelixFrameworkTestSuite.cc +++ b/libs/framework/gtest/src/CelixFrameworkTestSuite.cc @@ -30,28 +30,18 @@ #include "celix_constants.h" #include "celix_utils.h" - class CelixFrameworkTestSuite : public ::testing::Test { -public: + public: CelixFrameworkTestSuite() { - int rc; - celix_framework_t *fw = nullptr; - celix_bundle_context_t *context = nullptr; - - rc = celixLauncher_launch("config.properties", &fw); - EXPECT_EQ(CELIX_SUCCESS, rc); - - celix_bundle_t* bundle = celix_framework_getFrameworkBundle(fw); - EXPECT_TRUE(bundle != nullptr); + celix_properties_t* config; + auto status = celix_properties_load("config.properties", 0, &config); + EXPECT_EQ(CELIX_SUCCESS, status); - context = celix_framework_getFrameworkContext(fw); - EXPECT_TRUE(context != nullptr); + auto fw = celix_frameworkFactory_createFramework(config); + EXPECT_TRUE(fw != nullptr); - framework = std::shared_ptr{fw, [](celix_framework_t* cFw) { - celixLauncher_stop(cFw); - celixLauncher_waitForShutdown(cFw); - celixLauncher_destroy(cFw); - }}; + framework = std::shared_ptr{ + fw, [](celix_framework_t* cFw) { celix_frameworkFactory_destroyFramework(cFw); }}; } std::shared_ptr framework{}; @@ -104,7 +94,7 @@ TEST_F(CelixFrameworkTestSuite, AsyncInstallStartStopUpdateAndUninstallBundleTes EXPECT_TRUE(celix_framework_isBundleInstalled(framework.get(), bndId)); EXPECT_FALSE(celix_framework_isBundleActive(framework.get(), bndId)); - celix_framework_updateBundleAsync(framework.get(), bndId, NULL); + celix_framework_updateBundleAsync(framework.get(), bndId, nullptr); celix_framework_waitForBundleLifecycleHandlers(framework.get()); EXPECT_FALSE(celix_framework_isBundleActive(framework.get(), bndId)); @@ -112,7 +102,7 @@ TEST_F(CelixFrameworkTestSuite, AsyncInstallStartStopUpdateAndUninstallBundleTes celix_framework_waitForBundleLifecycleHandlers(framework.get()); EXPECT_TRUE(celix_framework_isBundleActive(framework.get(), bndId)); - celix_framework_updateBundleAsync(framework.get(), bndId, NULL); + celix_framework_updateBundleAsync(framework.get(), bndId, nullptr); celix_framework_waitForBundleLifecycleHandlers(framework.get()); EXPECT_TRUE(celix_framework_isBundleActive(framework.get(), bndId)); @@ -120,7 +110,7 @@ TEST_F(CelixFrameworkTestSuite, AsyncInstallStartStopUpdateAndUninstallBundleTes celix_framework_waitForBundleLifecycleHandlers(framework.get()); EXPECT_FALSE(celix_framework_isBundleActive(framework.get(), bndId)); - celix_framework_updateBundleAsync(framework.get(), bndId, NULL); + celix_framework_updateBundleAsync(framework.get(), bndId, nullptr); celix_framework_waitForBundleLifecycleHandlers(framework.get()); EXPECT_FALSE(celix_framework_isBundleActive(framework.get(), bndId)); @@ -324,7 +314,8 @@ TEST_F(FrameworkFactoryTestSuite, LaunchFrameworkWithConfigTest) { * the specified bundles will be installed and - if needed - started. */ - auto* config = celix_properties_load(INSTALL_AND_START_BUNDLES_CONFIG_PROPERTIES_FILE); + celix_properties_t* config = nullptr; + ASSERT_EQ(CELIX_SUCCESS, celix_properties_load(INSTALL_AND_START_BUNDLES_CONFIG_PROPERTIES_FILE, 0, &config)); ASSERT_TRUE(config != nullptr); framework_t* fw = celix_frameworkFactory_createFramework(config); diff --git a/libs/framework/gtest/src/CelixLauncherErrorInjectionTestSuite.cc b/libs/framework/gtest/src/CelixLauncherErrorInjectionTestSuite.cc new file mode 100644 index 000000000..416d753b6 --- /dev/null +++ b/libs/framework/gtest/src/CelixLauncherErrorInjectionTestSuite.cc @@ -0,0 +1,90 @@ +/* + * 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 + +#include "celix_launcher.h" +#include "celix_stdlib_cleanup.h" +#include "celix_utils.h" +#include "framework.h" +#include "celix_launcher_private.h" + +#include "celix_properties_ei.h" +#include "malloc_ei.h" + +#define LAUNCH_WAIT_TIMEOUT 100 + +class CelixLauncherErrorInjectionTestSuite : public ::testing::Test { + public: + CelixLauncherErrorInjectionTestSuite() { + celix_ei_expect_calloc(nullptr, 0, nullptr); + celix_ei_expect_celix_properties_setEntry(nullptr, 0, CELIX_SUCCESS); + } + + static int launch(const std::vector& args, celix_properties_t* props) { + celix_autofree char* str = nullptr; + if (props) { + EXPECT_EQ(CELIX_SUCCESS, celix_properties_saveToString(props, 0, &str)); + } + + char** argv = new char*[args.size()]; + for (size_t i = 0; i < args.size(); ++i) { + argv[i] = celix_utils_strdup(args[i].c_str()); + } + + auto rc = celix_launcher_launchAndWait((int)args.size(), argv, str); + + for (size_t i = 0; i < args.size(); ++i) { + free(argv[i]); + } + delete [] argv; + return rc; + } +}; + +TEST_F(CelixLauncherErrorInjectionTestSuite, CreateBundleCacheErrorTest) { + //Given an error injection for calloc is primed when called from framework_create + celix_ei_expect_calloc((void*)framework_create, 0, nullptr); + + //When calling celix_launcher_launchAndWait + auto rc = launch({"programName", "-c"}, nullptr); + + //Then an exception is expected + EXPECT_EQ(1, rc); +} + +TEST_F(CelixLauncherErrorInjectionTestSuite, CombinePropertiesErrorTest) { + //Given an error injection for celix_properties_setEntry is primed when called from celix_launcher_combineProperties + celix_ei_expect_celix_properties_setEntry((void*)celix_launcher_combineProperties, 0, ENOMEM); + + //When calling celix_launcher_launchAndWait with configuration properties + auto rc = launch({"programName"}, nullptr); + + //Then an exception is expected + EXPECT_EQ(1, rc); + + //Given an error injection for celix_properties_setEntry is primed when called from celix_launcher_combineProperties + celix_ei_expect_celix_properties_setEntry((void*)celix_launcher_combineProperties, 0, ENOMEM); + + //When calling celix_launcher_launchAndWait with a create cache flag + rc = launch({"programName", "-c"}, nullptr); + + //Then an exception is expected + EXPECT_EQ(1, rc); +} diff --git a/libs/framework/gtest/src/CelixLauncherTestSuite.cc b/libs/framework/gtest/src/CelixLauncherTestSuite.cc index b3a798902..55fc2cfbb 100644 --- a/libs/framework/gtest/src/CelixLauncherTestSuite.cc +++ b/libs/framework/gtest/src/CelixLauncherTestSuite.cc @@ -18,128 +18,245 @@ */ #include + #include +#include +#include +#include -#include "celix_launcher.h" #include "celix_constants.h" +#include "celix_launcher.h" +#include "celix_launcher_private.h" +#include "celix_stdlib_cleanup.h" #include "celix_utils.h" +#define LAUNCH_WAIT_TIMEOUT 100 -class CelixLauncherTestSuite : public ::testing::Test {}; +class CelixLauncherTestSuite : public ::testing::Test { + public: + static std::future launchInThread(const std::vector& args, celix_properties_t* props, int expectedRc) { + std::string propsStr{}; + if (props) { + celix_autofree char* str; + EXPECT_EQ(CELIX_SUCCESS, celix_properties_saveToString(props, 0, &str)); + propsStr = str; + celix_properties_destroy(props); + } + return std::async(std::launch::async, [args, propsStr, expectedRc] { + char** argv = new char*[args.size()]; + for (size_t i = 0; i < args.size(); ++i) { + argv[i] = celix_utils_strdup(args[i].c_str()); + } + const char* str = propsStr.empty() ? nullptr : propsStr.c_str(); + auto rc = celix_launcher_launchAndWait((int)args.size(), argv, str); + EXPECT_EQ(rc, expectedRc); + for (size_t i = 0; i < args.size(); ++i) { + free(argv[i]); + } + delete [] argv; + }); + } +}; TEST_F(CelixLauncherTestSuite, PrintPropertiesTest) { //launch framework with bundle configured to start //Given a properties set with 1 bundle configured for start and 1 bundle configured for install auto* props = celix_properties_create(); + ASSERT_TRUE(props != nullptr); celix_properties_set(props, CELIX_AUTO_START_0, SIMPLE_TEST_BUNDLE1_LOCATION); celix_properties_set(props, CELIX_AUTO_INSTALL, SIMPLE_TEST_BUNDLE2_LOCATION); - //When I run the celixLauncher with "-p" argument - char* arg1 = celix_utils_strdup("programName"); - char* arg2 = celix_utils_strdup("-p"); - char* argv[] = {arg1, arg2}; - int rc = celixLauncher_launchAndWaitForShutdown(2, argv, props); + //When I run the celixLauncher with "-p" argument and expect a 0 return code + auto future = launchInThread({"programName", "-p"}, props, 0); - //Then it will print the properties and exit with 0 - EXPECT_EQ(rc, 0); - free(arg1); - free(arg2); + //Then the launch will print the properties and exit + auto status = future.wait_for(std::chrono::milliseconds{LAUNCH_WAIT_TIMEOUT}); + EXPECT_EQ(status, std::future_status::ready); +} + +TEST_F(CelixLauncherTestSuite, PrintEmptyPropertiesTest) { + //launch framework with bundle configured to start + //Given an empty properties + auto* props = celix_properties_create(); + ASSERT_TRUE(props != nullptr); + + //When I run the celixLauncher with "-p" argument and expect a 0 return code + auto future = launchInThread({"programName", "-p", "empty.properties"}, props, 0); + + //Then the launch will print the properties and exit + auto status = future.wait_for(std::chrono::milliseconds{LAUNCH_WAIT_TIMEOUT}); + EXPECT_EQ(status, std::future_status::ready); } TEST_F(CelixLauncherTestSuite, PrintHelpTest) { // props should be released by launcher auto* props = celix_properties_create(); + ASSERT_TRUE(props != nullptr); celix_properties_set(props, CELIX_AUTO_START_0, SIMPLE_TEST_BUNDLE1_LOCATION); celix_properties_set(props, CELIX_AUTO_INSTALL, SIMPLE_TEST_BUNDLE2_LOCATION); - //When I run the celixLauncher with "-h" argument - char* arg1 = celix_utils_strdup("programName"); - char* arg2 = celix_utils_strdup("-h"); - char* argv[] = {arg1, arg2}; - int rc = celixLauncher_launchAndWaitForShutdown(2, argv, props); - - //Then it will print the usage and exit with 0 - EXPECT_EQ(rc, 0); - free(arg1); - free(arg2); + + //When I run the celixLauncher with "-h" argument and expect a 0 return code + auto future = launchInThread({"programName", "-h"}, props, 0); + + //Then the launch will print the help info and exit + auto status = future.wait_for(std::chrono::milliseconds{LAUNCH_WAIT_TIMEOUT}); + EXPECT_EQ(status, std::future_status::ready); } TEST_F(CelixLauncherTestSuite, ExtractBundlesTest) { //launch framework with bundle configured to start //Given a properties set with 2 bundles configured for start auto* props = celix_properties_create(); - auto start = std::string{} + SIMPLE_TEST_BUNDLE1_LOCATION + " " + SIMPLE_TEST_BUNDLE2_LOCATION; - celix_properties_set(props, CELIX_AUTO_START_0, start.c_str()); + ASSERT_TRUE(props != nullptr); + celix_properties_set(props, CELIX_AUTO_START_0, SIMPLE_TEST_BUNDLE1_LOCATION); + celix_properties_set(props, CELIX_AUTO_INSTALL, SIMPLE_TEST_BUNDLE2_LOCATION); + celix_autofree char* propsStr; + ASSERT_EQ(CELIX_SUCCESS, celix_properties_saveToString(props, 0, &propsStr)); - //When I run the celixLauncher with "-c" argument - char* arg1 = celix_utils_strdup("programName"); - char* arg2 = celix_utils_strdup("-c"); - char* argv[] = {arg1, arg2}; - int rc = celixLauncher_launchAndWaitForShutdown(2, argv, props); - - //Then it will print the result of the extracted bundles and exit with 0 - EXPECT_EQ(rc, 0); - free(arg1); - free(arg2); + //When I run the celixLauncher with "-c" argument and expect a 0 return code + auto future = launchInThread({"programName", "-c"}, props, 0); + + //Then the launch print the result of the extracted bundles and exit + auto status = future.wait_for(std::chrono::milliseconds{LAUNCH_WAIT_TIMEOUT}); + EXPECT_EQ(status, std::future_status::ready); } TEST_F(CelixLauncherTestSuite, ExtractNonexistentBundlesTest) { //launch framework with bundle configured to start - //Given a properties set with 2 bundles configured for start + //Given a properties set with a nonexistent bundle configured for start auto* props = celix_properties_create(); + ASSERT_TRUE(props != nullptr); auto start = std::string{} + "nonexistent"; celix_properties_set(props, CELIX_AUTO_START_0, start.c_str()); + celix_autofree char* propsStr; + ASSERT_EQ(CELIX_SUCCESS, celix_properties_saveToString(props, 0, &propsStr)); - //When I run the celixLauncher with "-c" argument - char* arg1 = celix_utils_strdup("programName"); - char* arg2 = celix_utils_strdup("-c"); - char* argv[] = {arg1, arg2}; - int rc = celixLauncher_launchAndWaitForShutdown(2, argv, props); - - //Then it will print the result of the extracted bundles and exit with 0 - EXPECT_EQ(rc, 1); - free(arg1); - free(arg2); + //When I run the celixLauncher with "-c" argument and expect a 1 return code + auto future = launchInThread({"programName", "-c"}, props, 1); + + //Then the launch will exit + auto status = future.wait_for(std::chrono::milliseconds{LAUNCH_WAIT_TIMEOUT}); + EXPECT_EQ(status, std::future_status::ready); } TEST_F(CelixLauncherTestSuite, ExtractBundlesIntoTempTest) { //launch framework with bundle configured to start //Given a properties set with 2 bundles configured for start + //And the CELIX_FRAMEWORK_CACHE_USE_TMP_DIR is set to true auto* props = celix_properties_create(); - auto start = std::string{} + SIMPLE_TEST_BUNDLE1_LOCATION + " " + SIMPLE_TEST_BUNDLE2_LOCATION; + ASSERT_TRUE(props != nullptr); + auto start = std::string{} + SIMPLE_TEST_BUNDLE1_LOCATION + "," + SIMPLE_TEST_BUNDLE2_LOCATION; celix_properties_set(props, CELIX_AUTO_START_0, start.c_str()); celix_properties_setBool(props, CELIX_FRAMEWORK_CACHE_USE_TMP_DIR, true); - //When I run the celixLauncher with "-c" argument - char* arg1 = celix_utils_strdup("programName"); - char* arg2 = celix_utils_strdup("-c"); - char* argv[] = {arg1, arg2}; - int rc = celixLauncher_launchAndWaitForShutdown(2, argv, props); - - //Then it will print the result of the extracted bundles and exit with 0 - EXPECT_EQ(rc, 1); - free(arg1); - free(arg2); + //When I run the celixLauncher with "-c" argument and expect a 1 return code, because + //extracting bundles to a temp dir is not supported. + auto future = launchInThread({"programName", "-c"}, props, 1); + + //Then the launch print the result of the extracted bundles and exit + auto status = future.wait_for(std::chrono::milliseconds{LAUNCH_WAIT_TIMEOUT}); + EXPECT_EQ(status, std::future_status::ready); } TEST_F(CelixLauncherTestSuite, LaunchCelixTest) { //launch framework with bundle configured to start //Given a properties set with 2 bundles configured for start auto* props = celix_properties_create(); + ASSERT_TRUE(props != nullptr); auto start = std::string{} + SIMPLE_TEST_BUNDLE1_LOCATION + " " + SIMPLE_TEST_BUNDLE2_LOCATION; celix_properties_set(props, CELIX_AUTO_START_0, start.c_str()); + celix_autofree char* propsStr; + ASSERT_EQ(CELIX_SUCCESS, celix_properties_saveToString(props, 0, &propsStr)); + + //When I run the celixLauncher with "-c" argument + auto future = launchInThread({"programName", "config.properties"}, props, 0); + + //Then the wait for the launch to finish will time out (framework is running) + auto status = future.wait_for(std::chrono::milliseconds{LAUNCH_WAIT_TIMEOUT}); + EXPECT_EQ(status, std::future_status::timeout); + + //When I stop the framework + celix_launcher_triggerStop(); + + //Then the launch will exit + status = future.wait_for(std::chrono::milliseconds{LAUNCH_WAIT_TIMEOUT}); + EXPECT_EQ(status, std::future_status::ready); +} + +TEST_F(CelixLauncherTestSuite, LaunchWithInvalidConfigPropertiesTest) { + //When launching the framework with an invalid config properties file + auto future = launchInThread({"programName", "invalid.properties"}, nullptr, 1); + + //Then the launch will exit + auto status = future.wait_for(std::chrono::milliseconds{LAUNCH_WAIT_TIMEOUT}); + EXPECT_EQ(status, std::future_status::ready); +} + +TEST_F(CelixLauncherTestSuite, StopLauncherWithSignalTest) { + // When launching the framework + auto future = launchInThread({"programName"}, nullptr, 0); + + // Then the launch will not exit, because the framework is running + auto status = future.wait_for(std::chrono::milliseconds{LAUNCH_WAIT_TIMEOUT}); + EXPECT_EQ(status, std::future_status::timeout); + + // When I stop the framework by mimicking a SIGINT signal + int signal = SIGINT; + celix_launcher_stopInternal(&signal); + + // Then the launch will exit + status = future.wait_for(std::chrono::milliseconds{LAUNCH_WAIT_TIMEOUT}); + EXPECT_EQ(status, std::future_status::ready); +} + +TEST_F(CelixLauncherTestSuite, DoubleStartAndStopLauncherTest) { + // When launching the framework + auto future = launchInThread({"programName"}, nullptr, 0); + + // Then the launch will not exit, because the framework is running + auto status = future.wait_for(std::chrono::milliseconds{LAUNCH_WAIT_TIMEOUT}); + EXPECT_EQ(status, std::future_status::timeout); + + //When I try start the framework again and expect a 1 return code (framework already running) + auto future2 = launchInThread({"programName"}, nullptr, 1); + + // The launch will exit + status = future2.wait_for(std::chrono::milliseconds{LAUNCH_WAIT_TIMEOUT}); + EXPECT_EQ(status, std::future_status::ready); + + // When I stop the framework + celix_launcher_triggerStop(); + + // Then the launch will exit + status = future.wait_for(std::chrono::milliseconds{LAUNCH_WAIT_TIMEOUT}); + EXPECT_EQ(status, std::future_status::ready); + + // When I try to stop the framework again + celix_launcher_triggerStop(); + + // Then nothing happens +} + +TEST_F(CelixLauncherTestSuite, StartWithInvalidEmbeddedPropertiesTest) { + //When launching the framework with an invalid embedded properties + auto rc = celix_launcher_launchAndWait(0, nullptr, "invalid props"); + + //Then the launch will exit with a return code of 1 + EXPECT_EQ(1, rc); +} + +TEST_F(CelixLauncherTestSuite, StartWithInvalidArgumentsTest) { + //When launching the framework with invalid arguments and expect a 1 return code + auto future = launchInThread({"programName", "config1.properties", "config2.properties"}, nullptr, 1); - //When I run the celixLauncher with "config.properties" argument - char* arg1 = celix_utils_strdup("programName"); - char* arg2 = celix_utils_strdup("config.properties"); - char* argv[] = {arg1, arg2}; - celix_framework_t* fw = nullptr; - int rc = celixLauncher_launchWithArgv(2, argv, props, &fw); - ASSERT_EQ(rc, 0); + // The launch will exit + auto status = future.wait_for(std::chrono::milliseconds{LAUNCH_WAIT_TIMEOUT}); + EXPECT_EQ(status, std::future_status::ready); - celixLauncher_stop(fw); - celixLauncher_waitForShutdown(fw); - celixLauncher_destroy(fw); + //When launching the framework with invalid arguments and expect a 1 return code + future = launchInThread({"programName", "-c", "-p"}, nullptr, 1); - free(arg1); - free(arg2); + // The launch will exit + status = future.wait_for(std::chrono::milliseconds{LAUNCH_WAIT_TIMEOUT}); + EXPECT_EQ(status, std::future_status::ready); } diff --git a/libs/framework/gtest/src/MultipleFrameworkTestSuite.cc b/libs/framework/gtest/src/MultipleFrameworkTestSuite.cc index 08b603adc..393ce42cc 100644 --- a/libs/framework/gtest/src/MultipleFrameworkTestSuite.cc +++ b/libs/framework/gtest/src/MultipleFrameworkTestSuite.cc @@ -27,30 +27,3 @@ class MultipleFrameworkTestSuite : public ::testing::Test { MultipleFrameworkTestSuite() = default; ~MultipleFrameworkTestSuite() noexcept override = default; }; - -TEST_F(MultipleFrameworkTestSuite, MultipleFrameworkTest) { - //framework 1 - celix_framework_t *framework1 = nullptr; - int rc = celixLauncher_launch("framework1.properties", &framework1); - ASSERT_EQ(CELIX_SUCCESS, rc); - celix_bundle_t* fwBundle1 = celix_framework_getFrameworkBundle(framework1); - EXPECT_NE(nullptr, fwBundle1); - celix_bundle_context_t* fwBundleContext1 = celix_framework_getFrameworkContext(framework1); - EXPECT_NE(nullptr, fwBundleContext1); - - //framework 2 - celix_framework_t *framework2 = nullptr; - rc = celixLauncher_launch("framework2.properties", &framework2); - celix_bundle_t* fwBundle2 = celix_framework_getFrameworkBundle(framework2); - EXPECT_NE(nullptr, fwBundle2); - celix_bundle_context_t* fwBundleContext2 = celix_framework_getFrameworkContext(framework2); - EXPECT_NE(nullptr, fwBundleContext2); - - celixLauncher_stop(framework1); - celixLauncher_waitForShutdown(framework1); - celixLauncher_destroy(framework1); - - celixLauncher_stop(framework2); - celixLauncher_waitForShutdown(framework2); - celixLauncher_destroy(framework2); -} diff --git a/libs/framework/include/celix/Constants.h b/libs/framework/include/celix/Constants.h index 9d5cccbac..b00fe8059 100644 --- a/libs/framework/include/celix/Constants.h +++ b/libs/framework/include/celix/Constants.h @@ -139,7 +139,7 @@ namespace celix { constexpr const char * const FRAMEWORK_STATIC_EVENT_QUEUE_SIZE = CELIX_FRAMEWORK_STATIC_EVENT_QUEUE_SIZE; /** - * @brief Celix framework environment property (named "CELIX_AUTO_START_0") which specified a (ordered) space + * @brief Celix framework environment property (named "CELIX_AUTO_START_0") which specified a (ordered) comma * separated set of bundles to load and auto start when the Celix framework is started. * * The Celix framework will first start bundles in for AUTO_START_0 and lastly start bundles in AUTO_START_6. @@ -181,7 +181,7 @@ 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 + * @brief Celix framework environment property (named "CELIX_AUTO_INSTALL") which specified a (ordered) comma * 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 diff --git a/libs/framework/include/celix_constants.h b/libs/framework/include/celix_constants.h index ae98e626e..ffc0abcfb 100644 --- a/libs/framework/include/celix_constants.h +++ b/libs/framework/include/celix_constants.h @@ -221,16 +221,16 @@ extern "C" { #define CELIX_FRAMEWORK_STATIC_EVENT_QUEUE_SIZE "CELIX_FRAMEWORK_STATIC_EVENT_QUEUE_SIZE" /** - * @brief Celix framework environment property (named "CELIX_AUTO_START_0") which specified a (ordered) space + * @brief Celix framework environment property (named "CELIX_AUTO_START_0") which specified a (ordered) comma * separated set of bundles to load and auto start when the Celix framework is started. * - * Note: Because the list is space separated path with spaces are not allowed. + * Note: Because the list is comma separated, paths with commas are not supported. * - * The Celix framework will first start bundles in for CELIX_AUTO_START_0 and lastly start bundles in CELIX_AUTO_START_6. - * Bundles which are also started in the order they appear in the AUTO_START set; first bundles mentioned is started + * The Celix framework will first start bundles in for CELIX_AUTO_START_0 and lastly start bundles in + * CELIX_AUTO_START_6. Bundles which are also started in the order they appear in the AUTO_START set; first bundles + * mentioned is started first. When the Celix framework stops the bundles are stopped in the reverse order. Bundles in + * CELIX_AUTO_START_6 are stopped first and of those bundles, the bundle mentioned last in a AUTO_START set is stopped * first. - * When the Celix framework stops the bundles are stopped in the reverse order. Bundles in CELIX_AUTO_START_6 are stopped - * first and of those bundles, the bundle mentioned last in a AUTO_START set is stopped first. */ #define CELIX_AUTO_START_0 "CELIX_AUTO_START_0" @@ -265,11 +265,11 @@ 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 + * @brief Celix framework environment property (named "CELIX_AUTO_INSTALL") which specified a (ordered) comma * 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. + * CELIX_AUTO_START_6 and then install (and 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. diff --git a/libs/framework/include/celix_launcher.h b/libs/framework/include/celix_launcher.h index 1eddf1945..97c6fa870 100644 --- a/libs/framework/include/celix_launcher.h +++ b/libs/framework/include/celix_launcher.h @@ -21,7 +21,6 @@ #ifndef CELIX_LAUNCHER_H #define CELIX_LAUNCHER_H -#include #include "celix_framework.h" #include "celix_framework_export.h" @@ -29,93 +28,35 @@ extern "C" { #endif - /** - * Launched a celix framework and wait (block) till the framework is stopped. - * The function will also destroy the framework when it has been stopped. + * @brief Launch a celix framework, wait (block) until the framework is stopped and destroy the framework when stopped. * * The launcher will also setup signal handlers for SIGINT, SIGTERM, SIGUSR1 and SIGUSR2 and initialize libcurl. - * For SIGINT and SIGTERM the framework will be stopped + * For SIGINT and SIGTERM the framework will be stopped. * SIGUSR1 and SIGUSR2 will be ignored. * + * The Celix launcher can only controls a single framework instance. If multiple frameworks are needed, + * `celix_frameworkFactory_createFramework` or `celix::createFramework` should be used. If the celix launcher is called + * while a framework is already running or being launched, the launcher will print an error message to stderr and + * return 1. * * @param argc argc as provided in a main function. * @param argv argv as provided in a main function. - * @param embeddedConfig The optional embedded config, will be overridden with the config.properties if found. - * @return 0 if successful. - */ -CELIX_FRAMEWORK_EXPORT int celixLauncher_launchAndWaitForShutdown(int argc, char *argv[], celix_properties_t *embeddedConfig); - - -/** - * Launched a celix framework using the provided argc/argv command line arguments and optional embedded config. - * - * Does not wait for the framework to be stopped, but returns the framework instance. - * - * @param[in] argc argc as provided in a main function. - * @param[in] argv argv as provided in a main function. - * @param[in] embeddedConfig The optional embedded config, will be overridden with the config.properties if found. - * @param[out] framework The framework instance. - * @return 0 if successful. - */ -CELIX_FRAMEWORK_EXPORT int celixLauncher_launchWithArgv(int argc, char *argv[], celix_properties_t* embeddedConfig, celix_framework_t** framework); - -/** - * Launches the a celix framework and returns the framework. - * - * The launcher will also setup signal handlers for SIGINT, SIGTERM, SIGUSR1 and SIGUSR2 and initialize libcurl. - * For SIGINT and SIGTERM the framework will be stopped - * SIGUSR1 and SIGUSR2 will be ignored. - * - * @param configFile Path to the config file (config.properties) - * @param framework Output parameter for the framework. - * @return 0 if successful. - */ -CELIX_FRAMEWORK_EXPORT int celixLauncher_launch(const char *configFile, celix_framework_t **framework); - -/** - * Launches the a celix framework and returns the framework. - * - * The launcher will also setup signal handlers for SIGINT, SIGTERM, SIGUSR1 and SIGUSR2 and initialize libcurl. - * For SIGINT and SIGTERM the framework will be stopped - * SIGUSR1 and SIGUSR2 will be ignored. - * - * @param config FILE* to the config file (config.properties) - * @param framework Output parameter for the framework. - * @return 0 if successful. + * @param embeddedConfig The optional embedded config text. + * @return 0 if successful and return 1 if the framework could not be launched. Reason for not launching the framework + * will be logged. */ -CELIX_FRAMEWORK_EXPORT int celixLauncher_launchWithStream(FILE *config, celix_framework_t **framework); +CELIX_FRAMEWORK_EXPORT int celix_launcher_launchAndWait(int argc, char* argv[], const char* embeddedConfig); /** - * Launches the a celix framework and returns the framework. + * @brief Trigger the stop of the Celix framework. * - * The launcher will also setup signal handlers for SIGINT, SIGTERM, SIGUSR1 and SIGUSR2 and initialize libcurl. - * For SIGINT and SIGTERM the framework will be stopped - * SIGUSR1 and SIGUSR2 will be ignored. + * Will trigger the global framework instance to stop. This will result in the framework to stop and the + * celix_launcher_launch function to return. * - * @param config the config properties. - * @param framework Output parameter for the framework. - * @return 0 if successful. - */ -CELIX_FRAMEWORK_EXPORT int celixLauncher_launchWithProperties(celix_properties_t *config, celix_framework_t **framework); - -/** - * Wait (blocks) for the shutdown of the provided celix framework. - * @param framework The framework to wait for. - */ -CELIX_FRAMEWORK_EXPORT void celixLauncher_waitForShutdown(celix_framework_t *framework); - -/** - * Stop the provided celix framework. - * @param framework The framework to stop. - */ -CELIX_FRAMEWORK_EXPORT void celixLauncher_stop(celix_framework_t *framework); - -/** - * Destroys the provided framework and if needed stops it first. - * @param framework The framework to stop. + * If no global framework instance is available, this function will print an error message to stderr. */ -CELIX_FRAMEWORK_EXPORT void celixLauncher_destroy(celix_framework_t *framework); +CELIX_FRAMEWORK_EXPORT void celix_launcher_triggerStop(); #ifdef __cplusplus } diff --git a/libs/framework/src/bundle.c b/libs/framework/src/bundle.c index 97a4f6e29..033a3541e 100644 --- a/libs/framework/src/bundle.c +++ b/libs/framework/src/bundle.c @@ -79,7 +79,7 @@ celix_status_t celix_bundle_createFromArchive(celix_framework_t *framework, bund } *bundleOut = bundle; - return status; + return status; } celix_status_t bundle_destroy(bundle_pt bundle) { diff --git a/libs/framework/src/bundle_archive.c b/libs/framework/src/bundle_archive.c index 688567345..8867e8038 100644 --- a/libs/framework/src/bundle_archive.c +++ b/libs/framework/src/bundle_archive.c @@ -18,7 +18,6 @@ */ #include -#include #include #include #include @@ -62,39 +61,52 @@ struct bundleArchive { static celix_status_t celix_bundleArchive_storeBundleStateProperties(bundle_archive_pt archive) { bool needUpdate = false; - celix_properties_t* bundleStateProperties = NULL; - bundleStateProperties = celix_properties_load(archive->savedBundleStatePropertiesPath); - if (bundleStateProperties == NULL) { - celix_framework_logTssErrors(archive->fw->logger, CELIX_LOG_LEVEL_ERROR); + celix_autoptr(celix_properties_t) bundleStateProperties = NULL; + if (celix_utils_fileExists(archive->savedBundleStatePropertiesPath)) { + celix_status_t status = + celix_properties_load(archive->savedBundleStatePropertiesPath, 0, &bundleStateProperties); + if (status != CELIX_SUCCESS) { + celix_framework_logTssErrors(archive->fw->logger, CELIX_LOG_LEVEL_ERROR); + } + } + if (!bundleStateProperties) { bundleStateProperties = celix_properties_create(); } - if (bundleStateProperties == NULL) { + if (!bundleStateProperties) { return CELIX_ENOMEM; } - //set/update bundle cache state properties - if (celix_properties_getAsLong(bundleStateProperties, CELIX_BUNDLE_ARCHIVE_BUNDLE_ID_PROPERTY_NAME, 0) != archive->id) { + + // set/update bundle cache state properties + if (celix_properties_getAsLong(bundleStateProperties, CELIX_BUNDLE_ARCHIVE_BUNDLE_ID_PROPERTY_NAME, 0) != + archive->id) { celix_properties_setLong(bundleStateProperties, CELIX_BUNDLE_ARCHIVE_BUNDLE_ID_PROPERTY_NAME, archive->id); needUpdate = true; } - if (strcmp(celix_properties_get(bundleStateProperties, CELIX_BUNDLE_ARCHIVE_LOCATION_PROPERTY_NAME, ""), archive->location) != 0) { + if (strcmp(celix_properties_get(bundleStateProperties, CELIX_BUNDLE_ARCHIVE_LOCATION_PROPERTY_NAME, ""), + archive->location) != 0) { celix_properties_set(bundleStateProperties, CELIX_BUNDLE_ARCHIVE_LOCATION_PROPERTY_NAME, archive->location); needUpdate = true; } - if (strcmp(celix_properties_get(bundleStateProperties, CELIX_BUNDLE_ARCHIVE_SYMBOLIC_NAME_PROPERTY_NAME, ""), archive->bundleSymbolicName) != 0) { - celix_properties_set(bundleStateProperties, CELIX_BUNDLE_ARCHIVE_SYMBOLIC_NAME_PROPERTY_NAME, archive->bundleSymbolicName); + if (strcmp(celix_properties_get(bundleStateProperties, CELIX_BUNDLE_ARCHIVE_SYMBOLIC_NAME_PROPERTY_NAME, ""), + archive->bundleSymbolicName) != 0) { + celix_properties_set( + bundleStateProperties, CELIX_BUNDLE_ARCHIVE_SYMBOLIC_NAME_PROPERTY_NAME, archive->bundleSymbolicName); needUpdate = true; } - if (strcmp(celix_properties_get(bundleStateProperties, CELIX_BUNDLE_ARCHIVE_VERSION_PROPERTY_NAME, ""), archive->bundleVersion) != 0) { + if (strcmp(celix_properties_get(bundleStateProperties, CELIX_BUNDLE_ARCHIVE_VERSION_PROPERTY_NAME, ""), + archive->bundleVersion) != 0) { celix_properties_set(bundleStateProperties, CELIX_BUNDLE_ARCHIVE_VERSION_PROPERTY_NAME, archive->bundleVersion); needUpdate = true; } - //save bundle cache state properties + // save bundle cache state properties if (needUpdate) { - celix_properties_store(bundleStateProperties, archive->savedBundleStatePropertiesPath, - "Bundle State Properties"); + celix_status_t status = celix_properties_save( + bundleStateProperties, archive->savedBundleStatePropertiesPath, CELIX_PROPERTIES_ENCODE_PRETTY); + if (status != CELIX_SUCCESS) { + return status; + } } - celix_properties_destroy(bundleStateProperties); return CELIX_SUCCESS; } @@ -317,14 +329,14 @@ celix_status_t celix_bundleArchive_create(celix_framework_t* fw, const char *arc celix_utils_deleteDirectory(archive->archiveRoot, NULL); } init_failed: - bundleArchive_destroy(archive); + celix_bundleArchive_destroy(archive); calloc_failed: celix_framework_logTssErrors(fw->logger, CELIX_LOG_LEVEL_ERROR); framework_logIfError(fw->logger, status, error, "Could not create archive."); return status; } -void bundleArchive_destroy(bundle_archive_pt archive) { +void celix_bundleArchive_destroy(bundle_archive_pt archive) { if (archive != NULL) { free(archive->location); free(archive->savedBundleStatePropertiesPath); diff --git a/libs/framework/src/bundle_archive_private.h b/libs/framework/src/bundle_archive_private.h index 7a2c774a8..e0d86acb7 100644 --- a/libs/framework/src/bundle_archive_private.h +++ b/libs/framework/src/bundle_archive_private.h @@ -49,7 +49,7 @@ extern "C" { */ celix_status_t celix_bundleArchive_create(celix_framework_t* fw, const char *archiveRoot, long id, const char *location, bundle_archive_pt *bundle_archive); -void bundleArchive_destroy(bundle_archive_pt archive); +void celix_bundleArchive_destroy(bundle_archive_pt archive); /** * @brief Returns the bundle id of the bundle archive. diff --git a/libs/framework/src/celix_bundle_cache.c b/libs/framework/src/celix_bundle_cache.c index d1917e2d2..cb0260c64 100644 --- a/libs/framework/src/celix_bundle_cache.c +++ b/libs/framework/src/celix_bundle_cache.c @@ -35,7 +35,7 @@ #include "framework_private.h" #include "bundle_archive_private.h" #include "celix_string_hash_map.h" -#include "celix_build_assert.h" +#include "celix_stdio_cleanup.h" //for Celix 3.0 update to a different bundle root scheme //#define CELIX_BUNDLE_ARCHIVE_ROOT_FORMAT "%s/bundle_%li" @@ -212,18 +212,18 @@ void celix_bundleCache_destroyArchive(celix_bundle_cache_t* cache, bundle_archiv } (void)celix_bundleArchive_removeInvalidDirs(archive); celixThreadMutex_unlock(&cache->mutex); - bundleArchive_destroy(archive); + celix_bundleArchive_destroy(archive); } /** * Update location->bundle id lookup map. */ -static void celix_bundleCache_updateIdForLocationLookupMap(celix_bundle_cache_t* cache) { - DIR* dir = opendir(cache->cacheDir); +static celix_status_t celix_bundleCache_updateIdForLocationLookupMap(celix_bundle_cache_t* cache) { + celix_autoptr(DIR) dir = opendir(cache->cacheDir); if (dir == NULL) { fw_logCode(cache->fw->logger, CELIX_LOG_LEVEL_ERROR, CELIX_BUNDLE_EXCEPTION, "Cannot open bundle cache directory %s", cache->cacheDir); - return; + return CELIX_FILE_IO_EXCEPTION; } char archiveRootBuffer[CELIX_DEFAULT_STRING_CREATE_BUFFER_SIZE]; struct dirent* dent = NULL; @@ -234,8 +234,16 @@ static void celix_bundleCache_updateIdForLocationLookupMap(celix_bundle_cache_t* char* bundleStateProperties = celix_utils_writeOrCreateString(archiveRootBuffer, sizeof(archiveRootBuffer), "%s/%s/%s", cache->cacheDir, dent->d_name, CELIX_BUNDLE_ARCHIVE_STATE_PROPERTIES_FILE_NAME); + celix_auto(celix_utils_string_guard_t) strGuard = celix_utils_stringGuard_init(archiveRootBuffer, bundleStateProperties); if (celix_utils_fileExists(bundleStateProperties)) { - celix_properties_t* props = celix_properties_load(bundleStateProperties); + celix_autoptr(celix_properties_t) props = NULL; + celix_status_t status = celix_properties_load(bundleStateProperties, 0, &props); + if (status != CELIX_SUCCESS) { + fw_logCode(cache->fw->logger, CELIX_LOG_LEVEL_ERROR, status, + "Cannot load bundle state properties from %s", bundleStateProperties); + celix_framework_logTssErrors(cache->fw->logger, CELIX_LOG_LEVEL_ERROR); + return status; + } const char* visitLoc = celix_properties_get(props, CELIX_BUNDLE_ARCHIVE_LOCATION_PROPERTY_NAME, NULL); long bndId = celix_properties_getAsLong(props, CELIX_BUNDLE_ARCHIVE_BUNDLE_ID_PROPERTY_NAME, -1); if (visitLoc != NULL && bndId >= 0) { @@ -243,25 +251,26 @@ static void celix_bundleCache_updateIdForLocationLookupMap(celix_bundle_cache_t* visitLoc, bndId); celix_stringHashMap_putLong(cache->locationToBundleIdLookupMap, visitLoc, bndId); } - celix_properties_destroy(props); } - celix_utils_freeStringIfNotEqual(archiveRootBuffer, bundleStateProperties); } - closedir(dir); + return CELIX_SUCCESS; } -long celix_bundleCache_findBundleIdForLocation(celix_bundle_cache_t* cache, const char* location) { - long bndId = -1; - celixThreadMutex_lock(&cache->mutex); +celix_status_t +celix_bundleCache_findBundleIdForLocation(celix_bundle_cache_t* cache, const char* location, long* outBndId) { + *outBndId = -1L; + celix_auto(celix_mutex_lock_guard_t) lck = celixMutexLockGuard_init(&cache->mutex); if (!cache->locationToBundleIdLookupMapLoaded) { - celix_bundleCache_updateIdForLocationLookupMap(cache); + celix_status_t status = celix_bundleCache_updateIdForLocationLookupMap(cache); + if (status != CELIX_SUCCESS) { + return status; + } cache->locationToBundleIdLookupMapLoaded = true; } if (celix_stringHashMap_hasKey(cache->locationToBundleIdLookupMap, location)) { - bndId = celix_stringHashMap_getLong(cache->locationToBundleIdLookupMap, location, -1); + *outBndId = celix_stringHashMap_getLong(cache->locationToBundleIdLookupMap, location, -1); } - celixThreadMutex_unlock(&cache->mutex); - return bndId; + return CELIX_SUCCESS; } bool celix_bundleCache_isBundleIdAlreadyUsed(celix_bundle_cache_t* cache, long bndId) { @@ -300,7 +309,7 @@ celix_bundleCache_createBundleArchivesForSpaceSeparatedList(celix_framework_t* f fw_log(fw->logger, lvl, "Created bundle cache '%s' for bundle archive %s (bndId=%li).", celix_bundleArchive_getCurrentRevisionRoot(archive), celix_bundleArchive_getSymbolicName(archive), celix_bundleArchive_getId(archive)); - bundleArchive_destroy(archive); + celix_bundleArchive_destroy(archive); } location = strtok_r(NULL, delims, &savePtr); } diff --git a/libs/framework/src/celix_bundle_cache.h b/libs/framework/src/celix_bundle_cache.h index fef8a7422..c6b559716 100644 --- a/libs/framework/src/celix_bundle_cache.h +++ b/libs/framework/src/celix_bundle_cache.h @@ -112,11 +112,13 @@ celix_status_t celix_bundleCache_deleteCacheDir(celix_bundle_cache_t* cache); * @brief Find if the there is already a bundle cache for the provided bundle zip location and if this is true * return the bundle id for the bundle cache entry. * - * @param cache The cache. - * @param location The location of the bundle zip to find the id for. - * @return The bundle id or -1 if not found. + * @param[in] cache The cache. + * @param[in] location The location of the bundle zip to find the id for. + * @param[out] outBndId The bundle id for the bundle cache entry. + * @return CELIX_SUCCESS if the bundle id is found and CELIX_FILE_IO_EXCEPTION if the cache cannot be opened or read. */ -long celix_bundleCache_findBundleIdForLocation(celix_bundle_cache_t* cache, const char* location); +celix_status_t +celix_bundleCache_findBundleIdForLocation(celix_bundle_cache_t* cache, const char* location, long* outBndId); /** * @brief Find if the there is already a bundle cache for the provided bundle id. diff --git a/libs/framework/src/celix_launcher.c b/libs/framework/src/celix_launcher.c index 8cf32a6f3..e0bb06c73 100644 --- a/libs/framework/src/celix_launcher.c +++ b/libs/framework/src/celix_launcher.c @@ -17,265 +17,387 @@ * under the License. */ - #include "celix_launcher.h" +#include "celix_launcher_private.h" +#include #include -#include #include +#include #include -#include #ifndef CELIX_NO_CURLINIT #include #endif -#include "framework.h" -#include "celix_framework_factory.h" +#include "celix_bundle_context.h" #include "celix_constants.h" +#include "celix_err.h" +#include "celix_file_utils.h" +#include "celix_framework_factory.h" #include "celix_framework_utils.h" -static void celixLauncher_shutdownFramework(int signal); -static void celixLauncher_ignore(int signal); -static int celixLauncher_launchWithConfigAndProps(const char *configFile, celix_framework_t* *framework, celix_properties_t* packedConfig); -static void celixLauncher_combineProperties(celix_properties_t *original, const celix_properties_t *append); -static celix_properties_t* celixLauncher_createConfig(const char* configFile, celix_properties_t* embeddedProperties); - -static void celixLauncher_printUsage(char* progName); -static void celixLauncher_printProperties(celix_properties_t *embeddedProps, const char* configFile); -static int celixLauncher_createBundleCache(celix_properties_t* embeddedProperties, const char* configFile); - #define DEFAULT_CONFIG_FILE "config.properties" #define CELIX_LAUNCHER_OK_EXIT_CODE 0 #define CELIX_LAUNCHER_ERROR_EXIT_CODE 1 -static framework_t *g_fw = NULL; +static bool g_framework_launched = false; +static framework_t* g_framework = NULL; +typedef struct { + bool showHelp; + bool showProps; + bool createCache; + const char* configFile; +} celix_launcher_options_t; +/** + * @brief SIGUSR1 SIGUSR2 no-op callback handler. + */ +static void celix_launcher_noopSignalHandler(int signal); -int celixLauncher_launchAndWaitForShutdown(int argc, char *argv[], celix_properties_t* packedConfig) { - celix_framework_t* framework = NULL; - int rc = celixLauncher_launchWithArgv(argc, argv, packedConfig, &framework); - if (rc == 0 && framework != NULL) { - celixLauncher_waitForShutdown(framework); - celixLauncher_destroy(framework); +/** + * @brief SIGINT SIGTERM callback to shutdown the framework. + */ +static void celix_launcher_shutdownFrameworkSignalHandler(int signal); + +/** + * @brief Check and set if a framework can be launched. + * @return true if the framework can be launched. + */ +static bool celix_launcher_checkFrameworkLaunched(); + +/** + * @brief Reset the launcher state. + */ +static void celix_launcher_resetLauncher(); + +/** + * @brief Create a Celix framework instance with the given embedded and runtime properties. + * + * Also: + * - Set up signal handlers for SIGINT and SIGTERM to stop the framework. + * - Set up signal handlers for SIGUSR1 and SIGUSR2 to ignore the signals. + * - If `CELIX_NO_CURLINIT` was not defined during compilation, initialize Curl. + */ +static celix_status_t celix_launcher_createFramework(celix_properties_t* embeddedProps, + const celix_properties_t* runtimeProps, + celix_framework_t** frameworkOut); + +/** + * @brief Parse launcher options from the given command line arguments. + */ +static celix_status_t celix_launcher_parseOptions(int argc, char* argv[], celix_launcher_options_t* opts); + +/** + * @brief Print the usage of the Celix launcher command arguments. + */ +static void celix_launcher_printUsage(char* progName); + +/** + * @brief Print the embedded, runtime and combined properties. + */ +static void celix_launcher_printProperties(const celix_properties_t* embeddedProps, + const celix_properties_t* runtimeProps, + const char* configFile); + + +/** + * @brief Create the bundle cache using the given embedded and runtime properties. + * + * Will create a framework instance to create the bundle cache and destroy the framework instance afterwards. + */ +static celix_status_t celix_launcher_createBundleCache(celix_properties_t* embeddedProps, const celix_properties_t* runtimeProps); + +/** + * @brief Load the runtime properties from the given file. + * + * If no file is given, a check is done for the default file and if it exists, the default file is used. + */ +static celix_status_t celix_launcher_loadRuntimeProperties(const char* configFile, celix_properties_t** outConfigProperties); + +/** + * @brief Set the global framework instance. + */ +static void celix_launcher_setGlobalFramework(celix_framework_t* fw); + +int celix_launcher_launchAndWait(int argc, char* argv[], const char* embeddedConfig) { + celix_autoptr(celix_properties_t) embeddedProps = NULL; + if (embeddedConfig) { + (void)celix_properties_loadFromString(embeddedConfig, 0, &embeddedProps); + } else { + embeddedProps = celix_properties_create(); + } + if (embeddedProps == NULL) { + celix_err_printErrors(stderr, "Error creating embedded properties: ", NULL); + return CELIX_LAUNCHER_ERROR_EXIT_CODE; + } + + celix_launcher_options_t options; + memset(&options, 0, sizeof(options)); + celix_status_t status = celix_launcher_parseOptions(argc, argv, &options); + if (status != CELIX_SUCCESS) { + return CELIX_LAUNCHER_ERROR_EXIT_CODE; + } + + celix_autoptr(celix_properties_t) runtimeProps = NULL; + status = celix_launcher_loadRuntimeProperties(options.configFile, &runtimeProps); + if (status != CELIX_SUCCESS) { + return CELIX_LAUNCHER_ERROR_EXIT_CODE; + } + + if (options.showHelp) { + celix_launcher_printUsage(argv[0]); + return CELIX_LAUNCHER_OK_EXIT_CODE; + } else if (options.showProps) { + celix_launcher_printProperties(embeddedProps, runtimeProps, options.configFile); + return CELIX_LAUNCHER_OK_EXIT_CODE; + } + + if (!celix_launcher_checkFrameworkLaunched()) { + return CELIX_LAUNCHER_ERROR_EXIT_CODE; + } + + if (options.createCache) { + status = celix_launcher_createBundleCache(celix_steal_ptr(embeddedProps), runtimeProps); + celix_launcher_resetLauncher(); + return status == CELIX_SUCCESS ? CELIX_LAUNCHER_OK_EXIT_CODE : CELIX_LAUNCHER_ERROR_EXIT_CODE; } - return rc; -} -int celixLauncher_launchWithArgv(int argc, - char* argv[], - celix_properties_t* embeddedConfig, - celix_framework_t** frameworkOut) { celix_framework_t* framework = NULL; + status = celix_launcher_createFramework(celix_steal_ptr(embeddedProps), runtimeProps, &framework); + if (status == CELIX_SUCCESS) { + celix_launcher_setGlobalFramework(framework); + celix_framework_waitForStop(framework); + celix_frameworkFactory_destroyFramework(framework); +#ifndef CELIX_NO_CURLINIT + // Cleanup Curl + curl_global_cleanup(); +#endif + celix_launcher_resetLauncher(); + } else { + celix_launcher_resetLauncher(); + } + return status == CELIX_SUCCESS ? CELIX_LAUNCHER_OK_EXIT_CODE : CELIX_LAUNCHER_ERROR_EXIT_CODE; +} +static celix_status_t celix_launcher_parseOptions(int argc, char* argv[], celix_launcher_options_t* opts) { // Perform some minimal command-line option parsing... - char* opt = NULL; - char* configFile = NULL; - bool showProps = false; - bool createCache = false; + int optCount = 0; for (int i = 1; i < argc; ++i) { - opt = argv[i]; + const char* opt = argv[i]; // Check whether the user wants some help... if (strncmp("-?", opt, sizeof("-?")) == 0 || strncmp("-h", opt, sizeof("-h")) == 0 || strncmp("--help", opt, sizeof("--help")) == 0) { - celixLauncher_printUsage(argv[0]); - celix_properties_destroy(embeddedConfig); - return CELIX_LAUNCHER_OK_EXIT_CODE; + opts->showHelp = true; + optCount++; } else if (strncmp("-p", opt, sizeof("-p")) == 0 || strncmp("--props", opt, sizeof("--props")) == 0) { - showProps = true; + opts->showProps = true; + optCount++; } else if (strncmp("-c", opt, sizeof("-c")) == 0 || strncmp("--create-bundle-cache", opt, sizeof("--create-bundle-cache")) == 0) { - createCache = true; + opts->createCache = true; + optCount++; } else { - configFile = opt; + if (opts->configFile) { + fprintf(stderr, "Error: multiple configuration files specified\n"); + return CELIX_ILLEGAL_ARGUMENT; + } + opts->configFile = opt; } } - if (configFile == NULL) { - configFile = DEFAULT_CONFIG_FILE; - } - - if (embeddedConfig == NULL) { - embeddedConfig = celix_properties_create(); + //check if not multiple options are set + if (optCount > 1) { + fprintf(stderr, "Error: multiple options specified\n"); + return CELIX_ILLEGAL_ARGUMENT; } - if (showProps) { - celixLauncher_printProperties(embeddedConfig, configFile); - celix_properties_destroy(embeddedConfig); - return CELIX_LAUNCHER_OK_EXIT_CODE; - } + return CELIX_SUCCESS; +} - if (createCache) { - return celixLauncher_createBundleCache(embeddedConfig, configFile); +static celix_status_t celix_launcher_createFramework(celix_properties_t* embeddedProps, + const celix_properties_t* runtimeProps, + celix_framework_t** frameworkOut) { + celix_status_t status = celix_launcher_combineProperties(embeddedProps, runtimeProps); + if (status != CELIX_SUCCESS) { + return status; } struct sigaction sigact; memset(&sigact, 0, sizeof(sigact)); - sigact.sa_handler = celixLauncher_shutdownFramework; + sigact.sa_handler = celix_launcher_shutdownFrameworkSignalHandler; sigaction(SIGINT, &sigact, NULL); sigaction(SIGTERM, &sigact, NULL); memset(&sigact, 0, sizeof(sigact)); - sigact.sa_handler = celixLauncher_ignore; + sigact.sa_handler = celix_launcher_noopSignalHandler; sigaction(SIGUSR1, &sigact, NULL); sigaction(SIGUSR2, &sigact, NULL); - int rc = celixLauncher_launchWithConfigAndProps(configFile, &framework, embeddedConfig); - if (rc == CELIX_LAUNCHER_OK_EXIT_CODE) { - g_fw = framework; - *frameworkOut = framework; - } - return rc; -} - -static void celixLauncher_shutdownFramework(int signal) { - if (g_fw != NULL) { - celixLauncher_stop(g_fw); //NOTE main thread will destroy - } -} - -static void celixLauncher_ignore(int signal) { - //ignoring for signal SIGUSR1, SIGUSR2. Can be used on threads -} - -int celixLauncher_launch(const char *configFile, celix_framework_t* *framework) { - return celixLauncher_launchWithConfigAndProps(configFile, framework, NULL); -} - -static int celixLauncher_launchWithConfigAndProps(const char *configFile, celix_framework_t** framework, celix_properties_t* packedConfig) { - celix_properties_t* config = celixLauncher_createConfig(configFile, packedConfig); - return celixLauncher_launchWithProperties(config, framework); -} - - -int celixLauncher_launchWithProperties(celix_properties_t* config, celix_framework_t** framework) { #ifndef CELIX_NO_CURLINIT - // Before doing anything else, let's setup Curl - curl_global_init(CURL_GLOBAL_ALL); + // Before doing anything else, lets setup Curl + curl_global_init(CURL_GLOBAL_ALL); #endif - *framework = celix_frameworkFactory_createFramework(config); - return *framework != NULL ? CELIX_LAUNCHER_OK_EXIT_CODE : CELIX_LAUNCHER_ERROR_EXIT_CODE; -} - -void celixLauncher_waitForShutdown(celix_framework_t* framework) { - celix_framework_waitForStop(framework); -} -void celixLauncher_destroy(celix_framework_t* framework) { - celix_frameworkFactory_destroyFramework(framework); -#ifndef CELIX_NO_CURLINIT - // Cleanup Curl - curl_global_cleanup(); -#endif + *frameworkOut = celix_frameworkFactory_createFramework(embeddedProps); + return *frameworkOut != NULL ? CELIX_SUCCESS : CELIX_FRAMEWORK_EXCEPTION; } -void celixLauncher_stop(celix_framework_t* framework) { - celix_framework_stopBundle(framework, CELIX_FRAMEWORK_BUNDLE_ID); +/** + * @brief SIGUSR1 SIGUSR2 no-op callback + */ +static void celix_launcher_noopSignalHandler(int signal __attribute__((unused))) { + // ignoring signal SIGUSR1, SIGUSR2. Can be used on threads } - -static void celixLauncher_printUsage(char* progName) { - printf("Usage:\n %s [-h|-p] [path/to/runtime/config.properties]\n", basename(progName)); +static void celix_launcher_printUsage(char* progName) { + printf("Usage:\n %s [-h|-p|-c] [path/to/runtime/config.properties]\n", basename(progName)); printf("Options:\n"); printf("\t-h | --help: Show this message.\n"); printf("\t-p | --props: Show the embedded and runtime properties for this Celix container and exit.\n"); printf("\t-c | --create-bundle-cache: Create the bundle cache for this Celix container and exit.\n"); - printf("\t--embedded_bundles: Show the embedded bundles for this Celix container and exit.\n"); printf("\n"); } -static void celixLauncher_printProperties(celix_properties_t *embeddedProps, const char *configFile) { - celix_properties_t *keys = celix_properties_create(); //only to store the keys +static void celix_launcher_printProperties(const celix_properties_t* embeddedProps, + const celix_properties_t* runtimeProps, + const char* configFile) { + celix_autoptr(celix_properties_t) keys = celix_properties_create(); // only to store the keys - printf("Embedded properties:\n"); - if (embeddedProps == NULL || celix_properties_size(embeddedProps) == 0) { - printf("|- Empty!\n"); - } else { + printf("Embedded properties:\n"); + if (embeddedProps == NULL || celix_properties_size(embeddedProps) == 0) { + printf("|- Empty!\n"); + } else { CELIX_PROPERTIES_ITERATE(embeddedProps, visit) { - printf("|- %s=%s\n", visit.key, visit.entry.value); + printf("|- %s=%s\n", visit.key, visit.entry.value); celix_properties_set(keys, visit.key, NULL); } - } - printf("\n"); - - celix_properties_t *runtimeProps = NULL; - if (configFile != NULL) { - runtimeProps = celix_properties_load(configFile); - } - printf("Runtime properties (input %s):\n", configFile); - if (runtimeProps == NULL || celix_properties_size(runtimeProps) == 0) { - printf("|- Empty!\n"); - } else { + } + printf("\n"); + + + printf("Runtime properties (input %s):\n", configFile ? configFile : "none"); + if (runtimeProps == NULL || celix_properties_size(runtimeProps) == 0) { + printf("|- Empty!\n"); + } else { CELIX_PROPERTIES_ITERATE(runtimeProps, visit) { - printf("|- %s=%s\n", visit.key, visit.entry.value); + printf("|- %s=%s\n", visit.key, visit.entry.value); celix_properties_set(keys, visit.key, NULL); } - } + } printf("\n"); - //combined result - printf("Resolved (env, runtime and embedded) properties:\n"); - if (celix_properties_size(keys) == 0) { - printf("|- Empty!\n"); - } else { + // combined result + printf("Resolved (env, runtime and embedded) properties:\n"); + if (celix_properties_size(keys) == 0) { + printf("|- Empty!\n"); + } else { CELIX_PROPERTIES_ITERATE(keys, visit) { - const char *valEm = celix_properties_get(embeddedProps, visit.key, NULL); - const char *valRt = celix_properties_get(runtimeProps, visit.key, NULL); - const char *envVal = getenv(visit.key); - const char *val = envVal != NULL ? envVal : valRt != NULL ? valRt : valEm; - const char *source = envVal != NULL ? "environment" : valRt != NULL ? "runtime" : "embedded"; - printf("|- %s=%s (source %s)\n", visit.key, val, source); - } - } + const char* valEm = celix_properties_get(embeddedProps, visit.key, NULL); + const char* valRt = celix_properties_get(runtimeProps, visit.key, NULL); + const char* envVal = getenv(visit.key); + const char* val = envVal != NULL ? envVal : valRt != NULL ? valRt : valEm; + const char* source = envVal != NULL ? "environment" : valRt != NULL ? "runtime" : "embedded"; + printf("|- %s=%s (source %s)\n", visit.key, val, source); + } + } printf("\n"); - - if (runtimeProps != NULL) { - celix_properties_destroy(runtimeProps); - } - celix_properties_destroy(keys); } -static int celixLauncher_createBundleCache(celix_properties_t* embeddedProperties, const char* configFile) { - celix_framework_t* fw = NULL; - celix_properties_t* config = celixLauncher_createConfig(configFile, embeddedProperties); - celix_status_t status = framework_create(&fw, config); +static celix_status_t celix_launcher_createBundleCache(celix_properties_t* embeddedProps, + const celix_properties_t* runtimeProps) { + celix_status_t status = celix_launcher_combineProperties(embeddedProps, runtimeProps); if (status != CELIX_SUCCESS) { + return status; + } + + celix_framework_t* fw = celix_frameworkFactory_createFramework(embeddedProps); + if (!fw) { fprintf(stderr, "Failed to create framework for bundle cache creation\n"); - return CELIX_LAUNCHER_ERROR_EXIT_CODE; + return CELIX_FRAMEWORK_EXCEPTION; } + status = celix_framework_utils_createBundleArchivesCache(fw); - (void)framework_destroy(fw); if (status != CELIX_SUCCESS) { - fprintf(stderr, "Failed to create bundle cache\n"); - return CELIX_LAUNCHER_ERROR_EXIT_CODE; + celix_bundle_context_t* ctx = celix_framework_getFrameworkContext(fw); + celix_bundleContext_log(ctx, CELIX_LOG_LEVEL_ERROR, "Failed to create bundle cache"); } - return CELIX_LAUNCHER_OK_EXIT_CODE; + celix_frameworkFactory_destroyFramework(fw); + return status; } -static void celixLauncher_combineProperties(celix_properties_t *original, const celix_properties_t *append) { - if (original != NULL && append != NULL) { - CELIX_PROPERTIES_ITERATE(append, visit) { - celix_properties_setEntry(original, visit.key, &visit.entry); - } - } +celix_status_t celix_launcher_combineProperties(celix_properties_t* embeddedProps, + const celix_properties_t* runtimeProps) { + if (embeddedProps && runtimeProps) { + CELIX_PROPERTIES_ITERATE(runtimeProps, visit) { + celix_status_t status = celix_properties_setEntry(embeddedProps, visit.key, &visit.entry); + if (status != CELIX_SUCCESS) { + celix_properties_destroy(embeddedProps); + return status; + } + } + } + return CELIX_SUCCESS; } -static celix_properties_t* celixLauncher_createConfig(const char* configFile, celix_properties_t* embeddedProperties) { - if (embeddedProperties == NULL) { - embeddedProperties = celix_properties_create(); +/** + * @brief Load the config properties from the given file. + * If configFile is NULL, config properties will only be loaded if DEFAULT_CONFIG_FILE exists. + */ +static celix_status_t celix_launcher_loadRuntimeProperties(const char* configFile, celix_properties_t** outConfigProperties) { + *outConfigProperties = NULL; + bool loadConfig = configFile != NULL; + if (!loadConfig) { + loadConfig = celix_utils_fileExists(DEFAULT_CONFIG_FILE); + configFile = DEFAULT_CONFIG_FILE; + } + if (loadConfig) { + celix_status_t status = celix_properties_load(configFile, 0, outConfigProperties); + if (status != CELIX_SUCCESS) { + celix_err_printErrors(stderr, "Error creating runtime properties: ", NULL); + return status; + } } + return CELIX_SUCCESS; +} + +static void celix_launcher_shutdownFrameworkSignalHandler(int signal) { + celix_launcher_stopInternal(&signal); +} + +void celix_launcher_triggerStop() { + celix_launcher_stopInternal(NULL); +} + +static void celix_launcher_setGlobalFramework(celix_framework_t* fw) { + __atomic_store_n(&g_framework, fw, __ATOMIC_SEQ_CST); +} - FILE *config = fopen(configFile, "r"); - if (config != NULL) { - celix_properties_t *configProps = celix_properties_loadWithStream(config); - fclose(config); - if (configProps != NULL) { - celixLauncher_combineProperties(embeddedProperties, configProps); - celix_properties_destroy(configProps); +void celix_launcher_stopInternal(const int* signal) { + celix_framework_t* fw = __atomic_exchange_n(&g_framework, NULL, __ATOMIC_SEQ_CST); + if (fw) { + if (signal) { + celix_bundle_context_t* ctx = celix_framework_getFrameworkContext(fw); + celix_bundleContext_log( + ctx, CELIX_LOG_LEVEL_INFO, "Stopping Celix framework due to signal %s", strsignal(*signal)); } + celix_framework_stopBundle(fw, CELIX_FRAMEWORK_BUNDLE_ID); + } else { + fprintf(stderr, "No global framework instance to stop\n"); } +} + +static bool celix_launcher_checkFrameworkLaunched() { + bool alreadyLaunched = __atomic_exchange_n(&g_framework_launched, true, __ATOMIC_SEQ_CST); + if (alreadyLaunched) { + fprintf(stderr, "Cannot launch framework, already launched\n"); + } + return !alreadyLaunched; +} - return embeddedProperties; +static void celix_launcher_resetLauncher() { + __atomic_store_n(&g_framework_launched, false, __ATOMIC_SEQ_CST); + __atomic_store_n(&g_framework, NULL, __ATOMIC_SEQ_CST); } diff --git a/libs/framework/src/celix_launcher_private.h b/libs/framework/src/celix_launcher_private.h new file mode 100644 index 000000000..8cb1d443f --- /dev/null +++ b/libs/framework/src/celix_launcher_private.h @@ -0,0 +1,49 @@ +/* +* 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_LAUNCHER_PRIVATE_H +#define CELIX_CELIX_LAUNCHER_PRIVATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Stop the framework, by stopping the framework bundle. + * + * Also logs a message if the framework is stopped due to a signal. + * + * @param signal The optional signal that caused the framework to stop. + */ +void celix_launcher_stopInternal(const int* signal); + +/** + * @brief Create a combined configuration properties set by combining the embedded properties with the runtime + * properties. + * @param[in,out] embeddedProps The embedded properties to use and extend with the runtime properties. + * @param[in] runtimeProps The optional runtime properties file to load and use. + */ +celix_status_t celix_launcher_combineProperties(celix_properties_t* embeddedProps, + const celix_properties_t* runtimeProps); + +#ifdef __cplusplus +} +#endif + +#endif // CELIX_CELIX_LAUNCHER_PRIVATE_H diff --git a/libs/framework/src/celix_log.c b/libs/framework/src/celix_log.c index c8606b43a..ebe3f236d 100644 --- a/libs/framework/src/celix_log.c +++ b/libs/framework/src/celix_log.c @@ -145,10 +145,10 @@ void celix_framework_logCode(celix_framework_logger_t* logger, celix_log_level_ void celix_framework_logTssErrors(celix_framework_logger_t* logger, celix_log_level_e level) { char buf[CELIX_ERR_BUFFER_SIZE] = {0}; - if (celix_err_dump(buf, sizeof(buf), "[TssErr] ", NULL) == 0) { + if (celix_err_dump(buf, sizeof(buf), NULL, NULL) == 0) { // nothing to output return; } celix_err_resetErrors(); - celix_framework_log(logger, level, NULL, NULL, 0, "Detected tss errors:\n%s", buf); + celix_framework_log(logger, level, NULL, NULL, 0, "Detected tss errors: %s", buf); } diff --git a/libs/framework/src/framework.c b/libs/framework/src/framework.c index 54e360595..797fce227 100644 --- a/libs/framework/src/framework.c +++ b/libs/framework/src/framework.c @@ -42,11 +42,12 @@ #include "bundle_archive_private.h" #include "bundle_context_private.h" #include "bundle_private.h" +#include "celix_err.h" +#include "celix_scheduled_event.h" +#include "celix_stdlib_cleanup.h" #include "framework_private.h" #include "service_reference_private.h" #include "service_registration_private.h" -#include "celix_scheduled_event.h" -#include "celix_err.h" #include "utils.h" struct celix_bundle_activator { @@ -59,10 +60,11 @@ struct celix_bundle_activator { }; static int celix_framework_eventQueueSize(celix_framework_t* fw); -static celix_status_t celix_framework_stopBundleEntryInternal(celix_framework_t* framework, celix_framework_bundle_entry_t* bndEntry); +static celix_status_t celix_framework_stopBundleEntryInternal(celix_framework_t* framework, + celix_bundle_entry_t* bndEntry); -static inline celix_framework_bundle_entry_t* fw_bundleEntry_create(celix_bundle_t *bnd) { - celix_framework_bundle_entry_t *entry = calloc(1, sizeof(*entry)); +static inline celix_bundle_entry_t* fw_bundleEntry_create(celix_bundle_t *bnd) { + celix_bundle_entry_t*entry = calloc(1, sizeof(*entry)); entry->bnd = bnd; celixThreadRwlock_create(&entry->fsmMutex, NULL); entry->bndId = celix_bundle_getId(bnd); @@ -72,7 +74,7 @@ static inline celix_framework_bundle_entry_t* fw_bundleEntry_create(celix_bundle return entry; } -static inline void fw_bundleEntry_destroy(celix_framework_bundle_entry_t *entry, bool wait) { +static inline void fw_bundleEntry_destroy(celix_bundle_entry_t*entry, bool wait) { celixThreadMutex_lock(&entry->useMutex); while (wait && entry->useCount != 0) { celixThreadCondition_wait(&entry->useCond, &entry->useMutex); @@ -86,14 +88,14 @@ static inline void fw_bundleEntry_destroy(celix_framework_bundle_entry_t *entry, free(entry); } -void celix_framework_bundleEntry_increaseUseCount(celix_framework_bundle_entry_t *entry) { +void celix_bundleEntry_increaseUseCount(celix_bundle_entry_t*entry) { assert(entry != NULL); celixThreadMutex_lock(&entry->useMutex); ++entry->useCount; celixThreadMutex_unlock(&entry->useMutex); } -void celix_framework_bundleEntry_decreaseUseCount(celix_framework_bundle_entry_t *entry) { +void celix_bundleEntry_decreaseUseCount(celix_bundle_entry_t*entry) { celixThreadMutex_lock(&entry->useMutex); assert(entry->useCount > 0); --entry->useCount; @@ -101,13 +103,13 @@ void celix_framework_bundleEntry_decreaseUseCount(celix_framework_bundle_entry_t celixThreadMutex_unlock(&entry->useMutex); } -celix_framework_bundle_entry_t* celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(celix_framework_t *fw, long bndId) { - celix_framework_bundle_entry_t* found = NULL; +celix_bundle_entry_t* celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(celix_framework_t *fw, long bndId) { + celix_bundle_entry_t* found = NULL; celixThreadMutex_lock(&fw->installedBundles.mutex); for (int i = 0; i < celix_arrayList_size(fw->installedBundles.entries); ++i) { - celix_framework_bundle_entry_t *entry = celix_arrayList_get(fw->installedBundles.entries, i); + celix_bundle_entry_t*entry = celix_arrayList_get(fw->installedBundles.entries, i); if (entry->bndId == bndId) { - celix_framework_bundleEntry_increaseUseCount(entry); + celix_bundleEntry_increaseUseCount(entry); found = entry; break; } @@ -120,7 +122,7 @@ bool celix_framework_isBundleIdAlreadyUsed(celix_framework_t *fw, long bndId) { bool found = false; celixThreadMutex_lock(&fw->installedBundles.mutex); for (int i = 0; i < celix_arrayList_size(fw->installedBundles.entries); ++i) { - celix_framework_bundle_entry_t *entry = celix_arrayList_get(fw->installedBundles.entries, i); + celix_bundle_entry_t*entry = celix_arrayList_get(fw->installedBundles.entries, i); if (entry->bndId == bndId) { found = true; break; @@ -130,11 +132,11 @@ bool celix_framework_isBundleIdAlreadyUsed(celix_framework_t *fw, long bndId) { return found; } -static inline bool fw_bundleEntry_removeBundleEntry(celix_framework_t *fw, celix_framework_bundle_entry_t* bndEntry) { +static inline bool fw_bundleEntry_removeBundleEntry(celix_framework_t *fw, celix_bundle_entry_t* bndEntry) { bool found = false; celixThreadMutex_lock(&fw->installedBundles.mutex); for (int i = 0; i < celix_arrayList_size(fw->installedBundles.entries); ++i) { - celix_framework_bundle_entry_t *entry = celix_arrayList_get(fw->installedBundles.entries, i); + celix_bundle_entry_t*entry = celix_arrayList_get(fw->installedBundles.entries, i); if (entry == bndEntry) { found = true; celix_arrayList_removeAt(fw->installedBundles.entries, i); @@ -151,17 +153,17 @@ long framework_getNextBundleId(framework_pt framework); celix_status_t fw_populateDependentGraph(framework_pt framework, bundle_pt exporter, hash_map_pt *map); -void fw_fireBundleEvent(framework_pt framework, bundle_event_type_e, celix_framework_bundle_entry_t* entry); +void fw_fireBundleEvent(framework_pt framework, bundle_event_type_e, celix_bundle_entry_t* entry); void fw_fireFrameworkEvent(framework_pt framework, framework_event_type_e eventType, celix_status_t errorCode); static void *fw_eventDispatcher(void *fw); celix_status_t fw_invokeBundleListener(framework_pt framework, bundle_listener_pt listener, bundle_event_pt event, bundle_pt bundle); celix_status_t fw_invokeFrameworkListener(framework_pt framework, framework_listener_pt listener, framework_event_pt event, bundle_pt bundle); -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 celix_status_t framework_autoStartConfiguredBundles(celix_framework_t *fw, bool* startedAllBundles); +static celix_status_t framework_autoInstallConfiguredBundles(celix_framework_t *fw, bool* installedAllBundles); +static bool framework_autoInstallConfiguredBundlesForList(celix_framework_t *fw, const char *autoStart, celix_array_list_t *installedBundles); +static bool 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); static void celix_framework_stopAndJoinEventQueue(celix_framework_t* fw); @@ -264,7 +266,7 @@ celix_status_t framework_create(framework_pt *out, celix_properties_t* config) { status = CELIX_DO_IF(status, bundle_setContext(framework->bundle, context)); //create framework bundle entry - celix_framework_bundle_entry_t *entry = fw_bundleEntry_create(framework->bundle); + celix_bundle_entry_t*entry = fw_bundleEntry_create(framework->bundle); celixThreadMutex_lock(&framework->installedBundles.mutex); celix_arrayList_add(framework->installedBundles.entries, entry); celixThreadMutex_unlock(&framework->installedBundles.mutex); @@ -298,7 +300,7 @@ celix_status_t framework_destroy(framework_pt framework) { celix_serviceRegistry_destroy(framework->registry); 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); + celix_bundle_entry_t*entry = celix_arrayList_get(framework->installedBundles.entries, i); celixThreadMutex_lock(&entry->useMutex); size_t count = entry->useCount; celixThreadMutex_unlock(&entry->useMutex); @@ -330,7 +332,7 @@ celix_status_t framework_destroy(framework_pt framework) { } if (archive) { - bundleArchive_destroy(archive); + celix_bundleArchive_destroy(archive); } bundle_destroy(bnd); @@ -452,76 +454,88 @@ celix_status_t framework_start(celix_framework_t* framework) { return status; } - celix_framework_bundle_entry_t* entry = + celix_bundle_entry_t* entry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(framework, framework->bundleId); fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_STARTED, entry); - celix_framework_bundleEntry_decreaseUseCount(entry); + celix_bundleEntry_decreaseUseCount(entry); - celix_status_t startStatus = framework_autoStartConfiguredBundles(framework); - celix_status_t installStatus = framework_autoInstallConfiguredBundles(framework); + bool allStarted = false; + status = framework_autoStartConfiguredBundles(framework, &allStarted); + bool allInstalled = false; + status = CELIX_DO_IF(status, framework_autoInstallConfiguredBundles(framework, &allInstalled)); + + if (status != CELIX_SUCCESS) { + fw_log(framework->logger, CELIX_LOG_LEVEL_ERROR, "Celix framework failed to start"); + return status; + } - if (startStatus == CELIX_SUCCESS && installStatus == CELIX_SUCCESS) { - //fire started event if all bundles are started/installed and the event queue is empty + if (allStarted && allInstalled) { + // fire started event if all bundles are started/installed and the event queue is empty celix_framework_waitForEmptyEventQueue(framework); fw_fireFrameworkEvent(framework, OSGI_FRAMEWORK_EVENT_STARTED, CELIX_SUCCESS); } else { - //note not returning an error, because the framework is started, but not all bundles are started/installed - fw_logCode(framework->logger, CELIX_LOG_LEVEL_ERROR, status, "Could not auto start or install all configured bundles"); + // note not returning an error, because the framework is started, but not all bundles are started/installed + fw_logCode( + framework->logger, CELIX_LOG_LEVEL_ERROR, status, "Could not auto start or install all configured bundles"); fw_fireFrameworkEvent(framework, OSGI_FRAMEWORK_EVENT_ERROR, CELIX_BUNDLE_EXCEPTION); } - 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)); - } else { - fw_log(framework->logger, CELIX_LOG_LEVEL_ERROR, "Celix framework failed to start"); - } + 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)); - return status; + return CELIX_SUCCESS; } -static celix_status_t framework_autoStartConfiguredBundles(celix_framework_t* fw) { +static celix_status_t framework_autoStartConfiguredBundles(celix_framework_t* fw, bool *startedAllBundles) { celix_status_t status = CELIX_SUCCESS; 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_array_list_t *installedBundles = celix_arrayList_create(); + celix_autoptr(celix_array_list_t) installedBundles = celix_arrayList_create(); + if (!installedBundles) { + celix_framework_logTssErrors(fw->logger, CELIX_LOG_LEVEL_ERROR); + return ENOMEM; + } + + bool allStarted = true; for (int i = 0; celixKeys[i] != NULL; ++i) { const char *autoStart = celix_framework_getConfigProperty(fw, celixKeys[i], NULL, NULL); if (autoStart != NULL) { - if (framework_autoInstallConfiguredBundlesForList(fw, autoStart, installedBundles) != CELIX_SUCCESS) { - status = CELIX_BUNDLE_EXCEPTION; + if (!framework_autoInstallConfiguredBundlesForList(fw, autoStart, installedBundles)) { + allStarted = false; } } } - celix_status_t startStatus = framework_autoStartConfiguredBundlesForList(fw, installedBundles); - if (status == CELIX_SUCCESS) { - status = startStatus; + if (!framework_autoStartConfiguredBundlesForList(fw, installedBundles)) { + allStarted = false; } - celix_arrayList_destroy(installedBundles); + *startedAllBundles = allStarted; return status; } -static celix_status_t framework_autoInstallConfiguredBundles(celix_framework_t* fw) { +static celix_status_t framework_autoInstallConfiguredBundles(celix_framework_t* fw, bool* installedAllBundles) { + *installedAllBundles = true; const char* autoInstall = celix_framework_getConfigProperty(fw, CELIX_AUTO_INSTALL, NULL, NULL); if (autoInstall != NULL) { - return framework_autoInstallConfiguredBundlesForList(fw, autoInstall, NULL); + *installedAllBundles = framework_autoInstallConfiguredBundlesForList(fw, autoInstall, NULL); } return CELIX_SUCCESS; } - -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; +static bool framework_autoInstallConfiguredBundlesForList(celix_framework_t* fw, + const char* autoStartIn, + celix_array_list_t* installedBundles) { + bool allInstalled = true; + const char* delim = ","; + char* save_ptr = NULL; char autoStartBuffer[CELIX_DEFAULT_STRING_CREATE_BUFFER_SIZE]; char* autoStart = celix_utils_writeOrCreateString(autoStartBuffer, sizeof(autoStartBuffer), "%s", autoStartIn); + celix_auto(celix_utils_string_guard_t) grd = celix_utils_stringGuard_init(autoStartBuffer, autoStart); if (autoStart != NULL) { - char *location = strtok_r(autoStart, delims, &save_ptr); + char* location = strtok_r(autoStart, delim, &save_ptr); while (location != NULL) { - //first install + // first install long id = -1L; if (celix_framework_installBundleInternal(fw, location, &id) == CELIX_SUCCESS) { if (installedBundles) { @@ -529,19 +543,21 @@ static celix_status_t framework_autoInstallConfiguredBundlesForList(celix_framew } } else { fw_log(fw->logger, CELIX_LOG_LEVEL_ERROR, "Could not install bundle from location '%s'.", location); - status = CELIX_BUNDLE_EXCEPTION; + allInstalled = false; } - location = strtok_r(NULL, delims, &save_ptr); + location = strtok_r(NULL, delim, &save_ptr); } } else { - fw_log(fw->logger, CELIX_LOG_LEVEL_ERROR, "Could not auto install bundles, out of memory."); + fw_log(fw->logger, CELIX_LOG_LEVEL_ERROR, "Could create auto install bundle list, out of memory."); + allInstalled = false; + // note out of memory, but framework can continue } - celix_utils_freeStringIfNotEqual(autoStartBuffer, autoStart); - return status;; + return allInstalled; } -static celix_status_t framework_autoStartConfiguredBundlesForList(celix_framework_t* fw, const celix_array_list_t *installedBundles) { - celix_status_t status = CELIX_SUCCESS; +static bool framework_autoStartConfiguredBundlesForList(celix_framework_t* fw, + const celix_array_list_t* installedBundles) { + bool allStarted = true; assert(!celix_framework_isCurrentThreadTheEventLoop(fw)); for (int i = 0; i < celix_arrayList_size(installedBundles); ++i) { long bndId = celix_arrayList_getLong(installedBundles, i); @@ -549,14 +565,21 @@ static celix_status_t framework_autoStartConfiguredBundlesForList(celix_framewor 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); + fw_log(fw->logger, + CELIX_LOG_LEVEL_ERROR, + "Could not start bundle %s (bnd id = %li)\n", + bnd->symbolicName, + bndId); + allStarted = false; } } 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; + fw_log(fw->logger, + CELIX_LOG_LEVEL_WARNING, + "Cannot start bundle %s (bnd id = %li) again, already started\n", bnd->symbolicName, + bndId); } } - return status; + return allStarted; } celix_status_t framework_stop(framework_pt framework) { @@ -624,63 +647,63 @@ bool celix_framework_getConfigPropertyAsBool(celix_framework_t* framework, const static celix_status_t celix_framework_installBundleInternalImpl(celix_framework_t* framework, const char* bndLoc, long* bndId) { - celix_status_t status = CELIX_SUCCESS; - celix_bundle_t* bundle = NULL; - long id = -1L; - - bundle_state_e state = CELIX_BUNDLE_STATE_UNKNOWN; - bool valid = celix_framework_utils_isBundleUrlValid(framework, bndLoc, false); if (!valid) { return CELIX_FILE_IO_EXCEPTION; } - //increase use count of framework bundle to prevent a stop. - celix_framework_bundle_entry_t *fwBundleEntry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(framework, - framework->bundleId); - status = CELIX_DO_IF(status, bundle_getState(framework->bundle, &state)); - if (status == CELIX_SUCCESS) { - if (state == CELIX_BUNDLE_STATE_STOPPING || state == CELIX_BUNDLE_STATE_UNINSTALLED) { - fw_log(framework->logger, CELIX_LOG_LEVEL_INFO, "The framework is being shutdown"); - status = CELIX_FRAMEWORK_SHUTDOWN; - } + // increase use count of framework bundle to prevent a stop. + celix_bundle_entry_t* fwBundleEntry = + celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(framework, framework->bundleId); + celix_auto(celix_bundle_entry_use_guard_t) fwEntryGuard = celix_bundleEntryUseGuard_init(fwBundleEntry); + + celix_bundle_state_e bndState = celix_bundle_getState(framework->bundle); + if (bndState == CELIX_BUNDLE_STATE_STOPPING || bndState == CELIX_BUNDLE_STATE_UNINSTALLED) { + fw_log(framework->logger, CELIX_LOG_LEVEL_INFO, "The framework is being shutdown"); + return CELIX_FRAMEWORK_SHUTDOWN; } - if (status == CELIX_SUCCESS) { - if (*bndId == -1L) { - id = framework_getBundle(framework, bndLoc); - if (id != -1L) { - celix_framework_bundleEntry_decreaseUseCount(fwBundleEntry); - *bndId = id; - return CELIX_SUCCESS; - } - long alreadyExistingBndId = celix_bundleCache_findBundleIdForLocation(framework->cache, bndLoc); - id = alreadyExistingBndId == -1 ? framework_getNextBundleId(framework) : alreadyExistingBndId; - } else { - id = *bndId; + long id; + if (*bndId == -1L) { + id = framework_getBundle(framework, bndLoc); + if (id != -1L) { + *bndId = id; + return CELIX_SUCCESS; } - bundle_archive_t* archive = NULL; - status = CELIX_DO_IF(status, celix_bundleCache_createArchive(framework->cache, id, bndLoc, &archive)); - status = CELIX_DO_IF(status, celix_bundle_createFromArchive(framework, archive, &bundle)); - if (status == CELIX_SUCCESS) { - celix_framework_bundle_entry_t *bEntry = fw_bundleEntry_create(bundle); - celix_framework_bundleEntry_increaseUseCount(bEntry); - celixThreadMutex_lock(&framework->installedBundles.mutex); - celix_arrayList_add(framework->installedBundles.entries, bEntry); - celixThreadMutex_unlock(&framework->installedBundles.mutex); - fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_INSTALLED, bEntry); - celix_framework_bundleEntry_decreaseUseCount(bEntry); + long alreadyExistingBndId; + celix_status_t status = + celix_bundleCache_findBundleIdForLocation(framework->cache, bndLoc, &alreadyExistingBndId); + if (status != CELIX_SUCCESS) { + fw_logCode(framework->logger, CELIX_LOG_LEVEL_ERROR, status, "Could not install bundle"); + return status; } + id = alreadyExistingBndId == -1 ? framework_getNextBundleId(framework) : alreadyExistingBndId; + } else { + id = *bndId; } - if (status == CELIX_SUCCESS) { - *bndId = id; - } else { - fw_logCode(framework->logger, CELIX_LOG_LEVEL_ERROR, status, "Could not install bundle"); + bundle_archive_t* archive = NULL; + celix_bundle_t* bundle = NULL; + celix_status_t status = celix_bundleCache_createArchive(framework->cache, id, bndLoc, &archive); + if (status != CELIX_SUCCESS) { + return status; + } + status = celix_bundle_createFromArchive(framework, archive, &bundle); + if (status != CELIX_SUCCESS) { + celix_bundleArchive_invalidate(archive); + celix_bundleCache_destroyArchive(framework->cache, archive); + return status; } - celix_framework_bundleEntry_decreaseUseCount(fwBundleEntry); - return status; + celix_bundle_entry_t*bEntry = fw_bundleEntry_create(bundle); + celix_bundleEntry_increaseUseCount(bEntry); + celixThreadMutex_lock(&framework->installedBundles.mutex); + celix_arrayList_add(framework->installedBundles.entries, bEntry); + celixThreadMutex_unlock(&framework->installedBundles.mutex); + fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_INSTALLED, bEntry); + celix_bundleEntry_decreaseUseCount(bEntry); + *bndId = id; + return CELIX_SUCCESS; } celix_status_t @@ -696,7 +719,7 @@ bool celix_framework_isBundleAlreadyInstalled(celix_framework_t* fw, const char* bool alreadyExists = false; celixThreadMutex_lock(&fw->installedBundles.mutex); for (int i = 0; i < celix_arrayList_size(fw->installedBundles.entries); ++i) { - celix_framework_bundle_entry_t *entry = celix_arrayList_get(fw->installedBundles.entries, i); + celix_bundle_entry_t*entry = celix_arrayList_get(fw->installedBundles.entries, i); if (celix_utils_stringEquals(entry->bnd->symbolicName, bundleSymbolicName)) { alreadyExists = true; break; @@ -763,19 +786,19 @@ celix_status_t fw_populateDependentGraph(framework_pt framework, bundle_pt expor } celix_status_t fw_registerService(framework_pt framework, service_registration_pt *registration, long bndId, const char* serviceName, const void* svcObj, celix_properties_t *properties) { - celix_status_t status = CELIX_SUCCESS; - char *error = NULL; - if (serviceName == NULL || svcObj == NULL) { - status = CELIX_ILLEGAL_ARGUMENT; - error = "ServiceName and SvcObj cannot be null"; - } + celix_status_t status = CELIX_SUCCESS; + char *error = NULL; + if (serviceName == NULL || svcObj == NULL) { + status = CELIX_ILLEGAL_ARGUMENT; + error = "ServiceName and SvcObj cannot be null"; + } - celix_framework_bundle_entry_t *entry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(framework, - bndId); + celix_bundle_entry_t*entry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(framework, + bndId); status = CELIX_DO_IF(status, serviceRegistry_registerService(framework->registry, entry->bnd, serviceName, svcObj, properties, registration)); - celix_framework_bundleEntry_decreaseUseCount(entry); + celix_bundleEntry_decreaseUseCount(entry); framework_logIfError(framework->logger, status, error, "Cannot register service: %s", serviceName); - return status; + return status; } celix_status_t fw_registerServiceFactory(framework_pt framework, service_registration_pt *registration, long bndId, const char* serviceName, service_factory_pt factory, celix_properties_t* properties) { @@ -786,12 +809,12 @@ celix_status_t fw_registerServiceFactory(framework_pt framework, service_registr error = "Service name and factory cannot be null"; } - celix_framework_bundle_entry_t *entry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(framework, + celix_bundle_entry_t*entry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(framework, bndId); status = CELIX_DO_IF(status, serviceRegistry_registerServiceFactory(framework->registry, entry->bnd, serviceName, factory, properties, registration)); - celix_framework_bundleEntry_decreaseUseCount(entry); + celix_bundleEntry_decreaseUseCount(entry); framework_logIfError(framework->logger, status, error, "Cannot register service factory: %s", serviceName); @@ -856,7 +879,7 @@ void fw_removeServiceListener(framework_pt framework, bundle_pt bundle CELIX_UNU celix_status_t fw_addBundleListener(framework_pt framework, bundle_pt bundle, bundle_listener_pt listener) { typedef struct { - celix_framework_bundle_entry_t* entry; + celix_bundle_entry_t* entry; celix_bundle_state_e currentState; } installed_bundle_entry_t; @@ -873,8 +896,8 @@ celix_status_t fw_addBundleListener(framework_pt framework, bundle_pt bundle, bu celixThreadMutex_lock(&framework->installedBundles.mutex); int size = celix_arrayList_size(framework->installedBundles.entries); for (int i = 0; i < size; ++i) { - celix_framework_bundle_entry_t *entry = celix_arrayList_get(framework->installedBundles.entries, i); - celix_framework_bundleEntry_increaseUseCount(entry); + celix_bundle_entry_t*entry = celix_arrayList_get(framework->installedBundles.entries, i); + celix_bundleEntry_increaseUseCount(entry); installed_bundle_entry_t* installedEntry = calloc(1, sizeof(*installedEntry)); installedEntry->entry = entry; installedEntry->currentState = celix_bundle_getState(entry->bnd); @@ -907,7 +930,7 @@ celix_status_t fw_addBundleListener(framework_pt framework, bundle_pt bundle, bu event.type = OSGI_FRAMEWORK_BUNDLE_EVENT_STARTED; listener->bundleChanged(listener, &event); } - celix_framework_bundleEntry_decreaseUseCount(installedEntry->entry); + celix_bundleEntry_decreaseUseCount(installedEntry->entry); free(installedEntry); } fw_bundleListener_decreaseUseCount(bundleListener); @@ -996,7 +1019,7 @@ static celix_status_t framework_markBundleResolved(framework_pt framework, modul if (bundle != NULL) { long bndId = celix_bundle_getId(bundle); - celix_framework_bundle_entry_t *entry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(framework,bndId); + celix_bundle_entry_t*entry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(framework,bndId); bundle_getState(bundle, &state); if (state != CELIX_BUNDLE_STATE_INSTALLED) { @@ -1022,8 +1045,7 @@ static celix_status_t framework_markBundleResolved(framework_pt framework, modul fw_logCode(framework->logger, CELIX_LOG_LEVEL_ERROR, status, "Could not resolve bundle: %s [%ld]", symbolicName, id); } - - celix_framework_bundleEntry_decreaseUseCount(entry); + celix_bundleEntry_decreaseUseCount(entry); } return status; @@ -1037,7 +1059,7 @@ celix_array_list_t* framework_getBundles(framework_pt framework) { celixThreadMutex_lock(&framework->installedBundles.mutex); int size = celix_arrayList_size(framework->installedBundles.entries); for (int i = 0; i < size; ++i) { - celix_framework_bundle_entry_t *entry = celix_arrayList_get(framework->installedBundles.entries, i); + celix_bundle_entry_t*entry = celix_arrayList_get(framework->installedBundles.entries, i); celix_arrayList_add(bundles, entry->bnd); } celixThreadMutex_unlock(&framework->installedBundles.mutex); @@ -1051,7 +1073,7 @@ long framework_getBundle(framework_pt framework, const char* location) { celixThreadMutex_lock(&framework->installedBundles.mutex); int size = celix_arrayList_size(framework->installedBundles.entries); for (int i = 0; i < size; ++i) { - celix_framework_bundle_entry_t *entry = celix_arrayList_get(framework->installedBundles.entries, i); + celix_bundle_entry_t*entry = celix_arrayList_get(framework->installedBundles.entries, i); const char *loc = NULL; bundle_getBundleLocation(entry->bnd, &loc); if (loc != NULL && location != NULL && strncmp(loc, location, strlen(loc)) == 0) { @@ -1090,12 +1112,12 @@ static void* framework_shutdown(void *framework) { celix_framework_waitForBundleLifecycleHandlers(fw); celix_array_list_t *stopEntries = celix_arrayList_create(); - celix_framework_bundle_entry_t *fwEntry = NULL; + celix_bundle_entry_t*fwEntry = NULL; celixThreadMutex_lock(&fw->installedBundles.mutex); int size = celix_arrayList_size(fw->installedBundles.entries); for (int i = 0; i < size; ++i) { - celix_framework_bundle_entry_t *entry = celix_arrayList_get(fw->installedBundles.entries, i); - celix_framework_bundleEntry_increaseUseCount(entry); + celix_bundle_entry_t*entry = celix_arrayList_get(fw->installedBundles.entries, i); + celix_bundleEntry_increaseUseCount(entry); if (entry->bndId != 0) { //i.e. not framework bundle celix_arrayList_add(stopEntries, entry); } else { @@ -1106,7 +1128,7 @@ static void* framework_shutdown(void *framework) { size = celix_arrayList_size(stopEntries); for (int i = size-1; i >= 0; --i) { //note loop in reverse order -> uninstall later installed bundle first - celix_framework_bundle_entry_t *entry = celix_arrayList_get(stopEntries, i); + celix_bundle_entry_t*entry = celix_arrayList_get(stopEntries, i); celix_framework_uninstallBundleEntry(fw, entry, false); } celix_arrayList_destroy(stopEntries); @@ -1117,7 +1139,7 @@ static void* framework_shutdown(void *framework) { // Lock the mutex to make sure that `celix_framework_stopBundleEntryInternal` on the framework has finished. celixThreadRwlock_readLock(&fwEntry->fsmMutex); celixThreadRwlock_unlock(&fwEntry->fsmMutex); - celix_framework_bundleEntry_decreaseUseCount(fwEntry); + celix_bundleEntry_decreaseUseCount(fwEntry); } //Now that all bundled has been stopped, no more events will be sent, we can safely stop the event dispatcher. celix_framework_stopAndJoinEventQueue(fw); @@ -1166,7 +1188,7 @@ bundle_context_t* framework_getContext(const_framework_pt framework) { return result; } -void fw_fireBundleEvent(framework_pt framework, bundle_event_type_e eventType, celix_framework_bundle_entry_t* entry) { +void fw_fireBundleEvent(framework_pt framework, bundle_event_type_e eventType, celix_bundle_entry_t* entry) { if (eventType == OSGI_FRAMEWORK_BUNDLE_EVENT_STOPPING || eventType == OSGI_FRAMEWORK_BUNDLE_EVENT_UNINSTALLED || eventType == OSGI_FRAMEWORK_BUNDLE_EVENT_STOPPED) { if (entry->bndId == framework->bundleId) { //NOTE for framework bundle not triggering events while framework is stopped (and as result in use) @@ -1174,7 +1196,7 @@ void fw_fireBundleEvent(framework_pt framework, bundle_event_type_e eventType, c } } - celix_framework_bundleEntry_increaseUseCount(entry); + celix_bundleEntry_increaseUseCount(entry); celix_framework_event_t event; memset(&event, 0, sizeof(event)); @@ -1335,7 +1357,7 @@ static inline void fw_handleEvents(celix_framework_t* framework) { bool dynamicallyAllocatedEvent = fw_removeTopEventFromQueue(framework); if (topEvent->bndEntry != NULL) { - celix_framework_bundleEntry_decreaseUseCount(topEvent->bndEntry); + celix_bundleEntry_decreaseUseCount(topEvent->bndEntry); } free(topEvent->serviceName); if (dynamicallyAllocatedEvent) { @@ -1559,7 +1581,7 @@ static size_t celix_framework_useBundlesInternal(framework_t *fw, bool includeFr celixThreadMutex_lock(&fw->installedBundles.mutex); int size = celix_arrayList_size(fw->installedBundles.entries); for (int i = 0; i < size; ++i) { - celix_framework_bundle_entry_t *entry = celix_arrayList_get(fw->installedBundles.entries, i); + celix_bundle_entry_t*entry = celix_arrayList_get(fw->installedBundles.entries, i); if (entry->bndId > 0 || includeFrameworkBundle) { celix_arrayList_addLong(bundleIds, entry->bndId); } @@ -1594,9 +1616,8 @@ size_t celix_framework_useActiveBundles(framework_t *fw, bool includeFrameworkBu bool celix_framework_useBundle(framework_t *fw, bool onlyActive, long bundleId, void *callbackHandle, void(*use)(void *handle, const bundle_t *bnd)) { bool called = false; if (bundleId >= 0) { - celix_framework_bundle_entry_t *entry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, + celix_bundle_entry_t*entry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bundleId); - if (entry != NULL) { if (onlyActive) { celixThreadRwlock_readLock(&entry->fsmMutex); @@ -1612,7 +1633,7 @@ bool celix_framework_useBundle(framework_t *fw, bool onlyActive, long bundleId, if (onlyActive) { celixThreadRwlock_unlock(&entry->fsmMutex); } - celix_framework_bundleEntry_decreaseUseCount(entry); + celix_bundleEntry_decreaseUseCount(entry); } else { framework_logIfError(fw->logger, CELIX_FRAMEWORK_EXCEPTION, NULL, "Bundle with id %li is not installed", bundleId); } @@ -1631,7 +1652,7 @@ long celix_framework_registerService(framework_t *fw, celix_bundle_t *bnd, const } long bndId = celix_bundle_getId(bnd); - celix_framework_bundle_entry_t *entry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bndId); + celix_bundle_entry_t*entry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bndId); if (factory != NULL) { @@ -1640,7 +1661,7 @@ long celix_framework_registerService(framework_t *fw, celix_bundle_t *bnd, const status = celix_serviceRegistry_registerService(fw->registry, bnd, serviceName, svc, properties, 0, ®); } - celix_framework_bundleEntry_decreaseUseCount(entry); + celix_bundleEntry_decreaseUseCount(entry); framework_logIfError(fw->logger, status, error, "Cannot register %s '%s'", factory == NULL ? "service" : "service factory", serviceName); @@ -1659,7 +1680,7 @@ long celix_framework_registerServiceAsync( void* eventDoneData, void (*eventDoneCallback)(void* eventDoneData)) { long bndId = celix_bundle_getId(bnd); - celix_framework_bundle_entry_t *entry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bndId); + celix_bundle_entry_t*entry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bndId); long svcId = celix_serviceRegistry_nextSvcId(fw->registry); @@ -1684,7 +1705,7 @@ long celix_framework_registerServiceAsync( void celix_framework_unregisterAsync(celix_framework_t* fw, celix_bundle_t* bnd, long serviceId, void *doneData, void (*doneCallback)(void*)) { long bndId = celix_bundle_getId(bnd); - celix_framework_bundle_entry_t *entry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bndId); + celix_bundle_entry_t*entry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bndId); celix_framework_event_t event; memset(&event, 0, sizeof(event)); @@ -1857,30 +1878,30 @@ celix_bundle_t* celix_framework_getFrameworkBundle(const celix_framework_t *fw) bundle_pt framework_getBundleById(framework_pt framework, long id) { celix_bundle_t *bnd = NULL; - celix_framework_bundle_entry_t *entry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(framework, id); + celix_bundle_entry_t*entry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(framework, id); if (entry != NULL) { bnd = entry->bnd; - celix_framework_bundleEntry_decreaseUseCount(entry); //NOTE returning bundle without increased use count -> FIXME make all getBundle api private (use bundle id instead) + celix_bundleEntry_decreaseUseCount(entry); //NOTE returning bundle without increased use count -> FIXME make all getBundle api private (use bundle id instead) } return bnd; } bool celix_framework_isBundleInstalled(celix_framework_t *fw, long bndId) { bool isInstalled = false; - celix_framework_bundle_entry_t *entry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bndId); + celix_bundle_entry_t*entry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bndId); if (entry != NULL) { isInstalled = true; - celix_framework_bundleEntry_decreaseUseCount(entry); + celix_bundleEntry_decreaseUseCount(entry); } return isInstalled; } bool celix_framework_isBundleActive(celix_framework_t *fw, long bndId) { bool isActive = false; - celix_framework_bundle_entry_t *entry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bndId); + celix_bundle_entry_t*entry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bndId); if (entry != NULL) { isActive = celix_bundle_getState(entry->bnd) == CELIX_BUNDLE_STATE_ACTIVE; - celix_framework_bundleEntry_decreaseUseCount(entry); + celix_bundleEntry_decreaseUseCount(entry); } return isActive; } @@ -1893,15 +1914,14 @@ static void celix_framework_waitForBundleEvents(celix_framework_t *fw, long bndI static long celix_framework_installAndStartBundleInternal(celix_framework_t *fw, const char *bundleLoc, bool autoStart, bool forcedAsync) { long bundleId = -1; - celix_status_t status = CELIX_SUCCESS; - - if (celix_framework_installBundleInternal(fw, bundleLoc, &bundleId) == CELIX_SUCCESS) { + celix_status_t status = celix_framework_installBundleInternal(fw, bundleLoc, &bundleId) ; + if (status == CELIX_SUCCESS) { if (autoStart) { - celix_framework_bundle_entry_t* bndEntry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, + celix_bundle_entry_t* bndEntry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bundleId); if (bndEntry != NULL) { status = celix_framework_startBundleOnANonCelixEventThread(fw, bndEntry, forcedAsync); - celix_framework_bundleEntry_decreaseUseCount(bndEntry); + celix_bundleEntry_decreaseUseCount(bndEntry); } else { status = CELIX_ILLEGAL_STATE; } @@ -1925,7 +1945,7 @@ long celix_framework_installBundleAsync(celix_framework_t *fw, const char *bundl static bool celix_framework_uninstallBundleInternal(celix_framework_t *fw, long bndId, bool forcedAsync, bool permanent) { bool uninstalled = false; - celix_framework_bundle_entry_t *bndEntry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bndId); + celix_bundle_entry_t*bndEntry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bndId); if (bndEntry != NULL) { celix_status_t status = celix_framework_uninstallBundleOnANonCelixEventThread(fw, bndEntry, forcedAsync, permanent); if (!forcedAsync) { @@ -1953,8 +1973,7 @@ void celix_framework_unloadBundleAsync(celix_framework_t *fw, long bndId) { celix_framework_uninstallBundleInternal(fw, bndId, true, false); } -static celix_status_t celix_framework_uninstallBundleEntryImpl(celix_framework_t* framework, - celix_framework_bundle_entry_t* bndEntry, +static celix_status_t celix_framework_uninstallBundleEntryImpl(celix_framework_t* framework, celix_bundle_entry_t* bndEntry, bool permanent) { assert(!celix_framework_isCurrentThreadTheEventLoop(framework)); @@ -1966,7 +1985,7 @@ static celix_status_t celix_framework_uninstallBundleEntryImpl(celix_framework_t if (!fw_bundleEntry_removeBundleEntry(framework, bndEntry)) { celixThreadRwlock_unlock(&bndEntry->fsmMutex); - celix_framework_bundleEntry_decreaseUseCount(bndEntry); + celix_bundleEntry_decreaseUseCount(bndEntry); return CELIX_ILLEGAL_STATE; } @@ -1992,7 +2011,7 @@ static celix_status_t celix_framework_uninstallBundleEntryImpl(celix_framework_t celixThreadRwlock_unlock(&bndEntry->fsmMutex); //NOTE wait outside installedBundles.mutex - celix_framework_bundleEntry_decreaseUseCount(bndEntry); + celix_bundleEntry_decreaseUseCount(bndEntry); fw_bundleEntry_destroy(bndEntry, true); //wait till use count is 0 -> e.g. not used if (status == CELIX_SUCCESS) { @@ -2008,7 +2027,7 @@ static celix_status_t celix_framework_uninstallBundleEntryImpl(celix_framework_t } -celix_status_t celix_framework_uninstallBundleEntry(celix_framework_t* framework, celix_framework_bundle_entry_t* bndEntry, bool permanent) { +celix_status_t celix_framework_uninstallBundleEntry(celix_framework_t* framework, celix_bundle_entry_t* bndEntry, bool permanent) { celix_status_t status = CELIX_SUCCESS; celixThreadMutex_lock(&framework->installLock); status = celix_framework_uninstallBundleEntryImpl(framework, bndEntry, permanent); @@ -2018,7 +2037,7 @@ celix_status_t celix_framework_uninstallBundleEntry(celix_framework_t* framework static bool celix_framework_stopBundleInternal(celix_framework_t* fw, long bndId, bool forcedAsync) { bool stopped = false; - celix_framework_bundle_entry_t *bndEntry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bndId); + celix_bundle_entry_t*bndEntry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bndId); if (bndEntry != NULL) { celix_bundle_state_e state = celix_bundle_getState(bndEntry->bnd); if (state == CELIX_BUNDLE_STATE_ACTIVE) { @@ -2029,7 +2048,7 @@ static bool celix_framework_stopBundleInternal(celix_framework_t* fw, long bndId } else { fw_log(fw->logger, CELIX_LOG_LEVEL_WARNING, "Cannot stop bundle, bundle state is %s", celix_bundleState_getName(state)); } - celix_framework_bundleEntry_decreaseUseCount(bndEntry); + celix_bundleEntry_decreaseUseCount(bndEntry); if (!forcedAsync) { celix_framework_waitForBundleEvents(fw, bndId); } @@ -2045,7 +2064,8 @@ void celix_framework_stopBundleAsync(celix_framework_t* fw, long bndId) { celix_framework_stopBundleInternal(fw, bndId, true); } -static celix_status_t celix_framework_stopBundleEntryInternal(celix_framework_t* framework, celix_framework_bundle_entry_t* bndEntry) { +static celix_status_t celix_framework_stopBundleEntryInternal(celix_framework_t* framework, + celix_bundle_entry_t* bndEntry) { celix_bundle_activator_t *activator = NULL; bundle_context_t *context = NULL; bool wasActive = false; @@ -2153,7 +2173,7 @@ static celix_status_t celix_framework_stopBundleEntryInternal(celix_framework_t* return status; } -celix_status_t celix_framework_stopBundleEntry(celix_framework_t* framework, celix_framework_bundle_entry_t* bndEntry) { +celix_status_t celix_framework_stopBundleEntry(celix_framework_t* framework, celix_bundle_entry_t* bndEntry) { celix_status_t status = CELIX_SUCCESS; assert(!celix_framework_isCurrentThreadTheEventLoop(framework)); celixThreadRwlock_writeLock(&bndEntry->fsmMutex); @@ -2164,14 +2184,14 @@ celix_status_t celix_framework_stopBundleEntry(celix_framework_t* framework, cel bool celix_framework_startBundleInternal(celix_framework_t *fw, long bndId, bool forcedAsync) { bool started = false; - celix_framework_bundle_entry_t *bndEntry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bndId); + celix_bundle_entry_t*bndEntry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bndId); if (bndEntry != NULL) { celix_bundle_state_e state = celix_bundle_getState(bndEntry->bnd); if (state == CELIX_BUNDLE_STATE_INSTALLED || state == CELIX_BUNDLE_STATE_RESOLVED) { celix_status_t rc = celix_framework_startBundleOnANonCelixEventThread(fw, bndEntry, forcedAsync); started = rc == CELIX_SUCCESS; } - celix_framework_bundleEntry_decreaseUseCount(bndEntry); + celix_bundleEntry_decreaseUseCount(bndEntry); if (!forcedAsync) { celix_framework_waitForBundleEvents(fw, bndId); } @@ -2187,8 +2207,7 @@ void celix_framework_startBundleAsync(celix_framework_t *fw, long bndId) { celix_framework_startBundleInternal(fw, bndId, true); } -static void celix_framework_printCelixErrForBundleEntry(celix_framework_t* framework, - celix_framework_bundle_entry_t* bndEntry) { +static void celix_framework_printCelixErrForBundleEntry(celix_framework_t* framework, celix_bundle_entry_t* bndEntry) { if (celix_err_getErrorCount() > 0) { celix_framework_log(framework->logger, CELIX_LOG_LEVEL_WARNING, NULL, NULL, 0, "Found unprocessed celix err messages for bundle %s [bndId=%li]. Unprocessed celix err messages:", @@ -2203,7 +2222,7 @@ static void celix_framework_printCelixErrForBundleEntry(celix_framework_t* frame } } -celix_status_t celix_framework_startBundleEntry(celix_framework_t* framework, celix_framework_bundle_entry_t* bndEntry) { +celix_status_t celix_framework_startBundleEntry(celix_framework_t* framework, celix_bundle_entry_t* bndEntry) { assert(!celix_framework_isCurrentThreadTheEventLoop(framework)); celix_status_t status = CELIX_SUCCESS; const char* error = ""; @@ -2332,7 +2351,7 @@ static bool celix_framework_updateBundleInternal(celix_framework_t *fw, long bnd return true; } bool updated = false; - celix_framework_bundle_entry_t *bndEntry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bndId); + celix_bundle_entry_t*bndEntry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bndId); if (bndEntry != NULL) { celix_status_t rc = celix_framework_updateBundleOnANonCelixEventThread(fw, bndEntry, updatedBundleUrl, forcedAsync); //note not decreasing bndEntry, because this entry should now be deleted (uninstalled) @@ -2345,61 +2364,68 @@ static bool celix_framework_updateBundleInternal(celix_framework_t *fw, long bnd } celix_status_t celix_framework_updateBundleEntry(celix_framework_t* framework, - celix_framework_bundle_entry_t* bndEntry, + celix_bundle_entry_t* bndEntry, const char* updatedBundleUrl) { celix_status_t status = CELIX_SUCCESS; long bundleId = bndEntry->bndId; - const char* errMsg; fw_log(framework->logger, CELIX_LOG_LEVEL_DEBUG, "Updating bundle %s", celix_bundle_getSymbolicName(bndEntry->bnd)); celix_bundle_state_e bndState = celix_bundle_getState(bndEntry->bnd); - char *location = celix_bundle_getLocation(bndEntry->bnd); - do { - // lock to reuse the bundle id - celixThreadMutex_lock(&framework->installLock); - if (updatedBundleUrl == NULL) { - updatedBundleUrl = location; - } else if (strcmp(location, updatedBundleUrl) != 0) { - long alreadyExistingBndId = celix_bundleCache_findBundleIdForLocation(framework->cache, updatedBundleUrl); - if (alreadyExistingBndId != -1 && alreadyExistingBndId != bundleId) { - errMsg = "specified bundle location exists in cache with a different id"; - celix_framework_bundleEntry_decreaseUseCount(bndEntry); - celixThreadMutex_unlock(&framework->installLock); - status = CELIX_ILLEGAL_STATE; - break; - } - celix_bundleArchive_invalidateCache(celix_bundle_getArchive(bndEntry->bnd)); - } - status = celix_framework_uninstallBundleEntryImpl(framework, bndEntry, false); - if (status != CELIX_SUCCESS) { - errMsg = "uninstall failure"; - celixThreadMutex_unlock(&framework->installLock); - break; - } - // bndEntry is now invalid - status = celix_framework_installBundleInternalImpl(framework, updatedBundleUrl, &bundleId); - if (status != CELIX_SUCCESS) { - errMsg = "reinstall failure"; - celixThreadMutex_unlock(&framework->installLock); - break; - } - if (bndState != CELIX_BUNDLE_STATE_STARTING && bndState != CELIX_BUNDLE_STATE_ACTIVE) { - // no need to restart the updated bundle - celixThreadMutex_unlock(&framework->installLock); - break; - } - celix_framework_bundle_entry_t* entry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(framework, bundleId); - celixThreadMutex_unlock(&framework->installLock); - // assert(entry != NULL); - status = celix_framework_startBundleEntry(framework, entry); - celix_framework_bundleEntry_decreaseUseCount(entry); - if (status != CELIX_SUCCESS) { - errMsg = "restart failure"; - break; - } - } while(0); - framework_logIfError(framework->logger, status, errMsg, "Could not update bundle from %s", updatedBundleUrl); - free(location); - return status; + celix_autofree char* location = celix_bundle_getLocation(bndEntry->bnd); + + // lock to reuse the bundle id + celix_auto(celix_mutex_lock_guard_t) lck = celixMutexLockGuard_init(&framework->installLock); + if (updatedBundleUrl == NULL) { + updatedBundleUrl = location; + } else if (strcmp(location, updatedBundleUrl) != 0) { + long existingBndId = -1L; + // celix_bundleCache_findBundleIdForLocation can never fail since there is at lease bndEntry is installed + (void)celix_bundleCache_findBundleIdForLocation(framework->cache, updatedBundleUrl, &existingBndId); + if (existingBndId != -1 && existingBndId != bundleId) { + fw_log(framework->logger, + CELIX_LOG_LEVEL_ERROR, + "Specified bundle location %s exists in cache with a different id. Update failed.", + updatedBundleUrl); + celix_bundleEntry_decreaseUseCount(bndEntry); + return CELIX_ILLEGAL_STATE; + } + celix_bundleArchive_invalidateCache(celix_bundle_getArchive(bndEntry->bnd)); + } + status = celix_framework_uninstallBundleEntryImpl(framework, bndEntry, false); + if (status != CELIX_SUCCESS) { + fw_log(framework->logger, CELIX_LOG_LEVEL_ERROR, "Failed to uninstall bundle id %li", bundleId); + return status; + } + + // bndEntry is now invalid + status = celix_framework_installBundleInternalImpl(framework, updatedBundleUrl, &bundleId); + if (status != CELIX_SUCCESS) { + fw_log(framework->logger, + CELIX_LOG_LEVEL_ERROR, + "Failed to install updated bundle %s", + updatedBundleUrl); + return status; + } + + if (bndState != CELIX_BUNDLE_STATE_STARTING && bndState != CELIX_BUNDLE_STATE_ACTIVE) { + // no need to restart the updated bundle + fw_log(framework->logger, CELIX_LOG_LEVEL_DEBUG, "Bundle %li is not active, no need to restart", bundleId); + return CELIX_SUCCESS; + } + + celix_bundle_entry_t* entry = + celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(framework, bundleId); + celix_auto(celix_bundle_entry_use_guard_t) entryGuard = celix_bundleEntryUseGuard_init(entry); + celixMutexLockGuard_deinit(&lck); + status = celix_framework_startBundleEntry(framework, entry); + if (status != CELIX_SUCCESS) { + fw_log(framework->logger, + CELIX_LOG_LEVEL_ERROR, + "Failed to start updated bundle %s", + celix_bundle_getSymbolicName(entry->bnd)); + return CELIX_BUNDLE_EXCEPTION; + } + + return CELIX_SUCCESS; } bool celix_framework_updateBundle(celix_framework_t *fw, long bndId, const char* updatedBundleUrl) { @@ -2414,7 +2440,7 @@ static celix_array_list_t* celix_framework_listBundlesInternal(celix_framework_t celix_array_list_t* result = celix_arrayList_create(); celix_auto(celix_mutex_lock_guard_t) lock = celixMutexLockGuard_init(&framework->installedBundles.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); + celix_bundle_entry_t* entry = celix_arrayList_get(framework->installedBundles.entries, i); if (entry->bndId == CELIX_FRAMEWORK_BUNDLE_ID) { continue; } @@ -2517,7 +2543,7 @@ long celix_framework_scheduleEvent(celix_framework_t* fw, return -1; } - celix_framework_bundle_entry_t* bndEntry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bndId); + celix_bundle_entry_t* bndEntry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bndId); if (bndEntry == NULL) { fw_log(fw->logger, CELIX_LOG_LEVEL_ERROR, "Cannot add scheduled event for non existing bundle id %li.", bndId); return -1; @@ -2534,7 +2560,7 @@ long celix_framework_scheduleEvent(celix_framework_t* fw, removeCallback); if (event == NULL) { - celix_framework_bundleEntry_decreaseUseCount(bndEntry); + celix_bundleEntry_decreaseUseCount(bndEntry); return -1L; //error logged by celix_scheduledEvent_create } @@ -2546,7 +2572,7 @@ long celix_framework_scheduleEvent(celix_framework_t* fw, id, celix_bundle_getSymbolicName(bndEntry->bnd), bndId); - celix_framework_bundleEntry_decreaseUseCount(bndEntry); + celix_bundleEntry_decreaseUseCount(bndEntry); celixThreadMutex_lock(&fw->dispatcher.mutex); celix_longHashMap_put(fw->dispatcher.scheduledEvents, id, event); @@ -2636,7 +2662,7 @@ void celix_framework_setLogCallback(celix_framework_t* fw, void* logHandle, void } long celix_framework_fireGenericEvent(framework_t* fw, long eventId, long bndId, const char *eventName, void* processData, void (*processCallback)(void *data), void* doneData, void (*doneCallback)(void* doneData)) { - celix_framework_bundle_entry_t* bndEntry = NULL; + celix_bundle_entry_t* bndEntry = NULL; if (bndId >=0) { bndEntry = celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(fw, bndId); if (bndEntry == NULL) { diff --git a/libs/framework/src/framework_bundle_lifecycle_handler.c b/libs/framework/src/framework_bundle_lifecycle_handler.c index 40caeb283..907b18ce0 100644 --- a/libs/framework/src/framework_bundle_lifecycle_handler.c +++ b/libs/framework/src/framework_bundle_lifecycle_handler.c @@ -41,22 +41,22 @@ static void* celix_framework_BundleLifecycleHandlingThread(void *data) { switch (handler->command) { case CELIX_BUNDLE_LIFECYCLE_START: celix_framework_startBundleEntry(handler->framework, handler->bndEntry); - celix_framework_bundleEntry_decreaseUseCount(handler->bndEntry); + celix_bundleEntry_decreaseUseCount(handler->bndEntry); break; case CELIX_BUNDLE_LIFECYCLE_STOP: celix_framework_stopBundleEntry(handler->framework, handler->bndEntry); - celix_framework_bundleEntry_decreaseUseCount(handler->bndEntry); + celix_bundleEntry_decreaseUseCount(handler->bndEntry); break; case CELIX_BUNDLE_LIFECYCLE_UNINSTALL: - celix_framework_bundleEntry_decreaseUseCount(handler->bndEntry); + celix_bundleEntry_decreaseUseCount(handler->bndEntry); celix_framework_uninstallBundleEntry(handler->framework, handler->bndEntry, true); break; case CELIX_BUNDLE_LIFECYCLE_UNLOAD: - celix_framework_bundleEntry_decreaseUseCount(handler->bndEntry); + celix_bundleEntry_decreaseUseCount(handler->bndEntry); celix_framework_uninstallBundleEntry(handler->framework, handler->bndEntry, false); break; default: //update - celix_framework_bundleEntry_decreaseUseCount(handler->bndEntry); + celix_bundleEntry_decreaseUseCount(handler->bndEntry); celix_framework_updateBundleEntry(handler->framework, handler->bndEntry, handler->updatedBundleUrl); break; } @@ -87,8 +87,9 @@ void celix_framework_waitForBundleLifecycleHandlers(celix_framework_t* fw) { celixThreadMutex_unlock(&fw->bundleLifecycleHandling.mutex); } -static void celix_framework_createAndStartBundleLifecycleHandler(celix_framework_t* fw, celix_framework_bundle_entry_t* bndEntry, enum celix_bundle_lifecycle_command bndCommand, const char* updatedBundleUrl) { - celix_framework_bundleEntry_increaseUseCount(bndEntry); +static void celix_framework_createAndStartBundleLifecycleHandler(celix_framework_t* fw, + celix_bundle_entry_t* bndEntry, enum celix_bundle_lifecycle_command bndCommand, const char* updatedBundleUrl) { + celix_bundleEntry_increaseUseCount(bndEntry); celixThreadMutex_lock(&fw->bundleLifecycleHandling.mutex); celix_framework_bundle_lifecycle_handler_t* handler = calloc(1, sizeof(*handler)); handler->command = bndCommand; @@ -106,7 +107,8 @@ static void celix_framework_createAndStartBundleLifecycleHandler(celix_framework celixThreadMutex_unlock(&fw->bundleLifecycleHandling.mutex); } -celix_status_t celix_framework_startBundleOnANonCelixEventThread(celix_framework_t* fw, celix_framework_bundle_entry_t* bndEntry, bool forceSpawnThread) { +celix_status_t celix_framework_startBundleOnANonCelixEventThread(celix_framework_t* fw, + celix_bundle_entry_t* bndEntry, bool forceSpawnThread) { if (forceSpawnThread) { fw_log(fw->logger, CELIX_LOG_LEVEL_TRACE, "start bundle from a separate thread"); celix_framework_createAndStartBundleLifecycleHandler(fw, bndEntry, CELIX_BUNDLE_LIFECYCLE_START, NULL); @@ -121,7 +123,8 @@ celix_status_t celix_framework_startBundleOnANonCelixEventThread(celix_framework } } -celix_status_t celix_framework_stopBundleOnANonCelixEventThread(celix_framework_t* fw, celix_framework_bundle_entry_t* bndEntry, bool forceSpawnThread) { +celix_status_t celix_framework_stopBundleOnANonCelixEventThread(celix_framework_t* fw, + celix_bundle_entry_t* bndEntry, bool forceSpawnThread) { if (forceSpawnThread) { fw_log(fw->logger, CELIX_LOG_LEVEL_TRACE, "stop bundle from a separate thread"); celix_framework_createAndStartBundleLifecycleHandler(fw, bndEntry, CELIX_BUNDLE_LIFECYCLE_STOP, NULL); @@ -136,7 +139,8 @@ celix_status_t celix_framework_stopBundleOnANonCelixEventThread(celix_framework_ } } -celix_status_t celix_framework_uninstallBundleOnANonCelixEventThread(celix_framework_t* fw, celix_framework_bundle_entry_t* bndEntry, bool forceSpawnThread, bool permanent) { +celix_status_t celix_framework_uninstallBundleOnANonCelixEventThread(celix_framework_t* fw, + celix_bundle_entry_t* bndEntry, bool forceSpawnThread, bool permanent) { if (forceSpawnThread) { fw_log(fw->logger, CELIX_LOG_LEVEL_TRACE, "uninstall bundle from a separate thread"); celix_framework_createAndStartBundleLifecycleHandler(fw, bndEntry, permanent ? CELIX_BUNDLE_LIFECYCLE_UNINSTALL : CELIX_BUNDLE_LIFECYCLE_UNLOAD, NULL); @@ -151,7 +155,8 @@ celix_status_t celix_framework_uninstallBundleOnANonCelixEventThread(celix_frame } } -celix_status_t celix_framework_updateBundleOnANonCelixEventThread(celix_framework_t* fw, celix_framework_bundle_entry_t* bndEntry, const char* updatedBundleUrl, bool forceSpawnThread) { +celix_status_t celix_framework_updateBundleOnANonCelixEventThread(celix_framework_t* fw, + celix_bundle_entry_t* bndEntry, const char* updatedBundleUrl, bool forceSpawnThread) { if (forceSpawnThread) { fw_log(fw->logger, CELIX_LOG_LEVEL_TRACE, "update bundle from a separate thread"); celix_framework_createAndStartBundleLifecycleHandler(fw, bndEntry, CELIX_BUNDLE_LIFECYCLE_UPDATE, updatedBundleUrl); diff --git a/libs/framework/src/framework_private.h b/libs/framework/src/framework_private.h index a00d6d8c6..457e16944 100644 --- a/libs/framework/src/framework_private.h +++ b/libs/framework/src/framework_private.h @@ -55,7 +55,7 @@ extern "C" { #define CELIX_FRAMEWORK_CACHE_USE_TMP_DIR_DEFAULT false #define CELIX_FRAMEWORK_CACHE_DIR_DEFAULT ".cache" -typedef struct celix_framework_bundle_entry { +typedef struct celix_bundle_entry { celix_bundle_t *bnd; celix_thread_rwlock_t fsmMutex; //protects bundle state transition long bndId; @@ -63,7 +63,7 @@ typedef struct celix_framework_bundle_entry { celix_thread_mutex_t useMutex; //protects useCount celix_thread_cond_t useCond; size_t useCount; -} celix_framework_bundle_entry_t; +} celix_bundle_entry_t; enum celix_framework_event_type { CELIX_FRAMEWORK_EVENT_TYPE = 0x01, @@ -77,7 +77,7 @@ typedef enum celix_framework_event_type celix_framework_event_type_e; struct celix_framework_event { celix_framework_event_type_e type; - celix_framework_bundle_entry_t* bndEntry; + celix_bundle_entry_t* bndEntry; void *doneData; void (*doneCallback)(void*); @@ -124,7 +124,7 @@ enum celix_bundle_lifecycle_command { typedef struct celix_framework_bundle_lifecycle_handler { celix_framework_t* framework; - celix_framework_bundle_entry_t* bndEntry; + celix_bundle_entry_t* bndEntry; long bndId; char* updatedBundleUrl; //only relevant and present for update command enum celix_bundle_lifecycle_command command; @@ -347,17 +347,45 @@ void celix_framework_waitForAsyncUnregistration(celix_framework_t *fw, long svcI /** * Increase the use count of a bundle and ensure that a bundle cannot be uninstalled. */ -void celix_framework_bundleEntry_increaseUseCount(celix_framework_bundle_entry_t *entry); +void celix_bundleEntry_increaseUseCount(celix_bundle_entry_t*entry); /** * Decrease the use count of a bundle. */ -void celix_framework_bundleEntry_decreaseUseCount(celix_framework_bundle_entry_t *entry); +void celix_bundleEntry_decreaseUseCount(celix_bundle_entry_t*entry); + +/** + * @brief Use guard for bundle entry usage. + */ +typedef struct celix_bundle_entry_use_guard { + celix_bundle_entry_t* entry; +} celix_bundle_entry_use_guard_t; + +/** + * @brief Initialize a bundle entry use guard. + */ +static CELIX_UNUSED inline celix_bundle_entry_use_guard_t celix_bundleEntryUseGuard_init(celix_bundle_entry_t* entry) { + celix_bundle_entry_use_guard_t guard; + guard.entry = entry; + return guard; +} + +/** + * @brief De-initialize a bundle entry use guard. + */ +static CELIX_UNUSED inline void celix_bundleEntryUseGuard_deinit(celix_bundle_entry_use_guard_t* guard) { + if (guard->entry) { + celix_bundleEntry_decreaseUseCount(guard->entry); + guard->entry = NULL; + } +} + +CELIX_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(celix_bundle_entry_use_guard_t, celix_bundleEntryUseGuard_deinit) /** * Find the bundle entry for the bnd id and increase use count */ -celix_framework_bundle_entry_t* celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(celix_framework_t *fw, long bndId); +celix_bundle_entry_t* celix_framework_bundleEntry_getBundleEntryAndIncreaseUseCount(celix_framework_t *fw, long bndId); /** * @brief Check if the bundle id is already in use. @@ -381,7 +409,8 @@ bool celix_framework_isBundleAlreadyInstalled(celix_framework_t* fw, const char* * @param forceSpawnThread If the true, the start bundle will always be done on a spawn thread * @return CELIX_SUCCESS of the call went alright. */ -celix_status_t celix_framework_startBundleOnANonCelixEventThread(celix_framework_t* fw, celix_framework_bundle_entry_t* bndEntry, bool forceSpawnThread); +celix_status_t celix_framework_startBundleOnANonCelixEventThread(celix_framework_t* fw, + celix_bundle_entry_t* bndEntry, bool forceSpawnThread); /** * Stop a bundle and ensure that this is not done on the Celix event thread. @@ -391,7 +420,8 @@ celix_status_t celix_framework_startBundleOnANonCelixEventThread(celix_framework * @param forceSpawnThread If the true, the start bundle will always be done on a spawn thread * @return CELIX_SUCCESS of the call went alright. */ -celix_status_t celix_framework_stopBundleOnANonCelixEventThread(celix_framework_t* fw, celix_framework_bundle_entry_t* bndEntry, bool forceSpawnThread); +celix_status_t celix_framework_stopBundleOnANonCelixEventThread(celix_framework_t* fw, + celix_bundle_entry_t* bndEntry, bool forceSpawnThread); /** * Uninstall (and if needed stop) a bundle and ensure that this is not done on the Celix event thread. @@ -402,7 +432,8 @@ celix_status_t celix_framework_stopBundleOnANonCelixEventThread(celix_framework_ * @param permanent If true, the bundle will be permanently uninstalled (e.g. the bundle archive will be removed). * @return CELIX_SUCCESS of the call went alright. */ -celix_status_t celix_framework_uninstallBundleOnANonCelixEventThread(celix_framework_t* fw, celix_framework_bundle_entry_t* bndEntry, bool forceSpawnThread, bool permanent); +celix_status_t celix_framework_uninstallBundleOnANonCelixEventThread(celix_framework_t* fw, + celix_bundle_entry_t* bndEntry, bool forceSpawnThread, bool permanent); /** * Update (and if needed stop and start) a bundle and ensure that this is not done on the Celix event thread. @@ -411,7 +442,8 @@ celix_status_t celix_framework_uninstallBundleOnANonCelixEventThread(celix_frame * @param forceSpawnThread If the true, the start bundle will always be done on a spawn thread * @return CELIX_SUCCESS of the call went alright. */ -celix_status_t celix_framework_updateBundleOnANonCelixEventThread(celix_framework_t* fw, celix_framework_bundle_entry_t* bndEntry, const char* updatedBundleUrl, bool forceSpawnThread); +celix_status_t celix_framework_updateBundleOnANonCelixEventThread(celix_framework_t* fw, + celix_bundle_entry_t* bndEntry, const char* updatedBundleUrl, bool forceSpawnThread); /** * Wait for all bundle lifecycle handlers finishing their jobs. @@ -422,22 +454,22 @@ void celix_framework_waitForBundleLifecycleHandlers(celix_framework_t* fw); /** * Start a bundle. Cannot be called on the Celix event thread. */ -celix_status_t celix_framework_startBundleEntry(celix_framework_t* fw, celix_framework_bundle_entry_t* bndEntry); +celix_status_t celix_framework_startBundleEntry(celix_framework_t* fw, celix_bundle_entry_t* bndEntry); /** * Stop a bundle. Cannot be called on the Celix event thread. */ -celix_status_t celix_framework_stopBundleEntry(celix_framework_t* fw, celix_framework_bundle_entry_t* bndEntry); +celix_status_t celix_framework_stopBundleEntry(celix_framework_t* fw, celix_bundle_entry_t* bndEntry); /** * Uninstall a bundle. Cannot be called on the Celix event thread. */ -celix_status_t celix_framework_uninstallBundleEntry(celix_framework_t* fw, celix_framework_bundle_entry_t* bndEntry, bool permanent); +celix_status_t celix_framework_uninstallBundleEntry(celix_framework_t* fw, celix_bundle_entry_t* bndEntry, bool permanent); /** * Update a bundle. Cannot be called on the Celix event thread. */ -celix_status_t celix_framework_updateBundleEntry(celix_framework_t* fw, celix_framework_bundle_entry_t* bndEntry, const char* updatedBundleUrl); +celix_status_t celix_framework_updateBundleEntry(celix_framework_t* fw, celix_bundle_entry_t* bndEntry, const char* updatedBundleUrl); /** @brief Return the next scheduled event id. diff --git a/libs/launcher/src/main.c b/libs/launcher/src/main.c index 6ae2f1b45..ffe9de1c8 100644 --- a/libs/launcher/src/main.c +++ b/libs/launcher/src/main.c @@ -23,7 +23,7 @@ int main(int argc, char *argv[]) { int ret; curl_global_init(CURL_GLOBAL_ALL); - ret = celixLauncher_launchAndWaitForShutdown(argc, argv, NULL); + ret = celix_launcher_launchAndWait(argc, argv, NULL); curl_global_cleanup(); return ret; } \ No newline at end of file diff --git a/libs/utils/error_injector/celix_properties/CMakeLists.txt b/libs/utils/error_injector/celix_properties/CMakeLists.txt index 7f65cd902..0155b75e7 100644 --- a/libs/utils/error_injector/celix_properties/CMakeLists.txt +++ b/libs/utils/error_injector/celix_properties/CMakeLists.txt @@ -26,5 +26,9 @@ target_link_options(properties_ei INTERFACE LINKER:--wrap,celix_properties_set LINKER:--wrap,celix_properties_setLong LINKER:--wrap,celix_properties_setVersion + LINKER:--wrap,celix_properties_setEntry + LINKER:--wrap,celix_properties_save + LINKER:--wrap,celix_properties_saveToStream + LINKER:--wrap,celix_properties_load ) add_library(Celix::properties_ei ALIAS properties_ei) diff --git a/libs/utils/error_injector/celix_properties/include/celix_properties_ei.h b/libs/utils/error_injector/celix_properties/include/celix_properties_ei.h index ad5f7184d..a98905c54 100644 --- a/libs/utils/error_injector/celix_properties/include/celix_properties_ei.h +++ b/libs/utils/error_injector/celix_properties/include/celix_properties_ei.h @@ -31,6 +31,10 @@ CELIX_EI_DECLARE(celix_properties_copy, celix_properties_t*); CELIX_EI_DECLARE(celix_properties_set, celix_status_t); CELIX_EI_DECLARE(celix_properties_setLong, celix_status_t); CELIX_EI_DECLARE(celix_properties_setVersion, celix_status_t); +CELIX_EI_DECLARE(celix_properties_setEntry, celix_status_t); +CELIX_EI_DECLARE(celix_properties_save, celix_status_t); +CELIX_EI_DECLARE(celix_properties_saveToStream, celix_status_t); +CELIX_EI_DECLARE(celix_properties_load, celix_status_t); #ifdef __cplusplus } diff --git a/libs/utils/error_injector/celix_properties/src/celix_properties_ei.cc b/libs/utils/error_injector/celix_properties/src/celix_properties_ei.cc index 1c9ace21c..c0bfe60a4 100644 --- a/libs/utils/error_injector/celix_properties/src/celix_properties_ei.cc +++ b/libs/utils/error_injector/celix_properties/src/celix_properties_ei.cc @@ -55,4 +55,46 @@ celix_status_t __wrap_celix_properties_setVersion(celix_properties_t *properties return __real_celix_properties_setVersion(properties, key, version); } +celix_status_t __real_celix_properties_setEntry(celix_properties_t* properties, + const char* key, + const celix_properties_entry_t* entry); +CELIX_EI_DEFINE(celix_properties_setEntry, celix_status_t) +celix_status_t __wrap_celix_properties_setEntry(celix_properties_t* properties, + const char* key, + const celix_properties_entry_t* entry) { + CELIX_EI_IMPL(celix_properties_setEntry); + return __real_celix_properties_setEntry(properties, key, entry); +} + +celix_status_t +__real_celix_properties_save(const celix_properties_t* properties, const char* filename, int encodeFlags); +CELIX_EI_DEFINE(celix_properties_save, celix_status_t) +celix_status_t +__wrap_celix_properties_save(const celix_properties_t* properties, const char* filename, int encodeFlags) { + CELIX_EI_IMPL(celix_properties_save); + return __real_celix_properties_save(properties, filename, encodeFlags); +} + +celix_status_t +__real_celix_properties_saveToStream(const celix_properties_t* properties, FILE* stream, int encodeFlags); +CELIX_EI_DEFINE(celix_properties_saveToStream, celix_status_t) +celix_status_t +__wrap_celix_properties_saveToStream(const celix_properties_t* properties, FILE* stream, int encodeFlags) { + CELIX_EI_IMPL(celix_properties_saveToStream); + return __real_celix_properties_saveToStream(properties, stream, encodeFlags); +} + +celix_status_t +__real_celix_properties_load(const char* filename, + int decodeFlags, + celix_properties_t** out); +CELIX_EI_DEFINE(celix_properties_load, celix_status_t) +celix_status_t +__wrap_celix_properties_load(const char* filename, + int decodeFlags, + celix_properties_t** out) { + CELIX_EI_IMPL(celix_properties_load); + return __real_celix_properties_load(filename, decodeFlags, out); +} + } \ No newline at end of file diff --git a/libs/utils/error_injector/celix_version/CMakeLists.txt b/libs/utils/error_injector/celix_version/CMakeLists.txt index 81886a5f8..b62253295 100644 --- a/libs/utils/error_injector/celix_version/CMakeLists.txt +++ b/libs/utils/error_injector/celix_version/CMakeLists.txt @@ -23,6 +23,7 @@ target_link_libraries(version_ei PUBLIC Celix::error_injector Celix::utils) target_link_options(version_ei INTERFACE LINKER:--wrap,celix_version_createVersionFromString LINKER:--wrap,celix_version_parse + LINKER:--wrap,celix_version_tryParse LINKER:--wrap,celix_version_copy LINKER:--wrap,celix_version_toString ) diff --git a/libs/utils/error_injector/celix_version/include/celix_version_ei.h b/libs/utils/error_injector/celix_version/include/celix_version_ei.h index e5d510f74..bc42768e6 100644 --- a/libs/utils/error_injector/celix_version/include/celix_version_ei.h +++ b/libs/utils/error_injector/celix_version/include/celix_version_ei.h @@ -29,6 +29,8 @@ CELIX_EI_DECLARE(celix_version_createVersionFromString, celix_version_t*); CELIX_EI_DECLARE(celix_version_parse, celix_status_t); +CELIX_EI_DECLARE(celix_version_tryParse, celix_status_t); + CELIX_EI_DECLARE(celix_version_copy, celix_version_t*); CELIX_EI_DECLARE(celix_version_toString, char*); diff --git a/libs/utils/error_injector/celix_version/src/celix_version_ei.cc b/libs/utils/error_injector/celix_version/src/celix_version_ei.cc index b09339cda..c43d8e739 100644 --- a/libs/utils/error_injector/celix_version/src/celix_version_ei.cc +++ b/libs/utils/error_injector/celix_version/src/celix_version_ei.cc @@ -34,6 +34,13 @@ celix_status_t __wrap_celix_version_parse(const char* versionStr, celix_version_ return __real_celix_version_parse(versionStr, version); } +celix_status_t __real_celix_version_tryParse(const char* versionStr, celix_version_t** version); +CELIX_EI_DEFINE(celix_version_tryParse, celix_status_t) +celix_status_t __wrap_celix_version_tryParse(const char* versionStr, celix_version_t** version) { + CELIX_EI_IMPL(celix_version_tryParse); + return __real_celix_version_tryParse(versionStr, version); +} + celix_version_t* __real_celix_version_copy(const celix_version_t* version); CELIX_EI_DEFINE(celix_version_copy, celix_version_t*) celix_version_t* __wrap_celix_version_copy(const celix_version_t* version) { diff --git a/libs/utils/gtest/CMakeLists.txt b/libs/utils/gtest/CMakeLists.txt index 0d717e1fa..be04e0a75 100644 --- a/libs/utils/gtest/CMakeLists.txt +++ b/libs/utils/gtest/CMakeLists.txt @@ -56,8 +56,8 @@ if (CELIX_CXX17) endif () ####### generating zip file used for testing ########################################################################## -file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/zip_content/top.properties" CONTENT "level=1\n") -file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/zip_content/subdir/sub.properties" CONTENT "level=2\n") +file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/zip_content/top.properties" CONTENT "{\"level\":1}") +file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/zip_content/subdir/sub.properties" CONTENT "{\"level\":2}") set(TEST_ZIP_FILE "${CMAKE_CURRENT_BINARY_DIR}/test.zip") if(ZIP_COMMAND) add_custom_command(OUTPUT ${TEST_ZIP_FILE} diff --git a/libs/utils/gtest/src/CelixUtilsAutoCleanupTestSuite.cc b/libs/utils/gtest/src/CelixUtilsAutoCleanupTestSuite.cc index a74a6f331..5f02a9a99 100644 --- a/libs/utils/gtest/src/CelixUtilsAutoCleanupTestSuite.cc +++ b/libs/utils/gtest/src/CelixUtilsAutoCleanupTestSuite.cc @@ -193,3 +193,7 @@ TEST_F(CelixUtilsCleanupTestSuite, StealFdTest) { TEST_F(CelixUtilsCleanupTestSuite, FileTest) { celix_autoptr(FILE) file = tmpfile(); } + +TEST_F(CelixUtilsCleanupTestSuite, DirTest) { + celix_autoptr(DIR) dir = opendir("."); +} diff --git a/libs/utils/gtest/src/ConvertUtilsErrorInjectionTestSuite.cc b/libs/utils/gtest/src/ConvertUtilsErrorInjectionTestSuite.cc index 259362e97..76a3659a1 100644 --- a/libs/utils/gtest/src/ConvertUtilsErrorInjectionTestSuite.cc +++ b/libs/utils/gtest/src/ConvertUtilsErrorInjectionTestSuite.cc @@ -30,6 +30,7 @@ class ConvertUtilsWithErrorInjectionTestSuite : public ::testing::Test { ~ConvertUtilsWithErrorInjectionTestSuite() override { celix_ei_expect_celix_version_copy(nullptr, 0, nullptr); celix_ei_expect_celix_version_createVersionFromString(nullptr, 0, CELIX_SUCCESS); + celix_ei_expect_celix_version_parse(nullptr, 0, CELIX_SUCCESS); celix_ei_expect_celix_arrayList_createWithOptions(nullptr, 0, nullptr); celix_ei_expect_celix_arrayList_createLongArray(nullptr, 0, nullptr); celix_ei_expect_celix_arrayList_addLong(nullptr, 0, CELIX_SUCCESS); diff --git a/libs/utils/gtest/src/ConvertUtilsTestSuite.cc b/libs/utils/gtest/src/ConvertUtilsTestSuite.cc index d3e8658cb..9aeb0cc67 100644 --- a/libs/utils/gtest/src/ConvertUtilsTestSuite.cc +++ b/libs/utils/gtest/src/ConvertUtilsTestSuite.cc @@ -235,7 +235,7 @@ TEST_F(ConvertUtilsTestSuite, ConvertToVersionTest) { convertStatus = celix_utils_convertStringToVersion("A", nullptr, &result); EXPECT_EQ(CELIX_ILLEGAL_ARGUMENT, convertStatus); EXPECT_EQ(nullptr, result); - EXPECT_STREQ("Invalid version component(0)", celix_err_popLastError()); + EXPECT_NE(nullptr, strstr(celix_err_popLastError(), "Invalid version part 0.")); //test for a string with a number convertStatus = celix_utils_convertStringToVersion("1.2.3.A", nullptr, &result); @@ -271,13 +271,13 @@ TEST_F(ConvertUtilsTestSuite, ConvertToVersionTest) { EXPECT_NE(nullptr, result); checkVersion(result, 1, 2, 3, "B"); //default version celix_version_destroy(result); - EXPECT_STREQ("Invalid version component(0)", celix_err_popLastError()); + EXPECT_NE(nullptr, strstr(celix_err_popLastError(), "Invalid version part 0.")); //test for a convert with a version value with trailing chars convertStatus = celix_utils_convertStringToVersion("2.1.1 and something else", nullptr, &result); EXPECT_EQ(CELIX_ILLEGAL_ARGUMENT, convertStatus); EXPECT_EQ(nullptr, result); - EXPECT_STREQ("Invalid trailing string:< and something else>", celix_err_popLastError()); + EXPECT_NE(nullptr, strstr(celix_err_popLastError(), "Invalid trailing string")); //test for a convert with a version value with trailing whitespaces convertStatus = celix_utils_convertStringToVersion("1.2.3 \t\n", nullptr, &result); diff --git a/libs/utils/gtest/src/CxxPropertiesTestSuite.cc b/libs/utils/gtest/src/CxxPropertiesTestSuite.cc index 1e65bb4f7..c95986743 100644 --- a/libs/utils/gtest/src/CxxPropertiesTestSuite.cc +++ b/libs/utils/gtest/src/CxxPropertiesTestSuite.cc @@ -325,25 +325,3 @@ TEST_F(CxxPropertiesTestSuite, ArrayListTest) { EXPECT_EQ(versions.size(), 1); EXPECT_EQ(versions[0], checkVersion); } - -TEST_F(CxxPropertiesTestSuite, StoreAndLoadTest) { - std::string path{"cxx_store_and_load_test.properties"}; - - celix::Properties props{}; - props.set("key1", "1"); - props.set("key2", "2"); - - EXPECT_NO_THROW(props.store(path)); - - celix::Properties loadedProps{}; - EXPECT_NO_THROW(loadedProps = celix::Properties::load(path)); - EXPECT_TRUE(loadedProps == props); - - try { - loadedProps = celix::Properties::load("non-existence"); - (void)loadedProps; - FAIL() << "Expected exception not thrown"; - } catch (const celix::IOException& e) { - EXPECT_TRUE(strstr(e.what(), "Cannot load celix::Properties")); - } -} diff --git a/libs/utils/gtest/src/FileUtilsTestSuite.cc b/libs/utils/gtest/src/FileUtilsTestSuite.cc index 6ff80d79c..d40cccda8 100644 --- a/libs/utils/gtest/src/FileUtilsTestSuite.cc +++ b/libs/utils/gtest/src/FileUtilsTestSuite.cc @@ -178,13 +178,14 @@ TEST_F(FileUtilsTestSuite, ExtractZipFileTest) { EXPECT_EQ(status, CELIX_SUCCESS); EXPECT_TRUE(celix_utils_fileExists(file1)); - auto* props = celix_properties_load(file1); - EXPECT_NE(props, nullptr); + celix_properties_t* props = nullptr; + EXPECT_EQ(CELIX_SUCCESS, celix_properties_load(file1, 0, &props)); EXPECT_EQ(celix_properties_getAsLong(props, "level", 0), 1); celix_properties_destroy(props); EXPECT_TRUE(celix_utils_fileExists(file2)); - props = celix_properties_load(file2); + props = nullptr; + EXPECT_EQ(CELIX_SUCCESS, celix_properties_load(file2, 0, &props)); EXPECT_NE(props, nullptr); EXPECT_EQ(celix_properties_getAsLong(props, "level", 0), 2); celix_properties_destroy(props); @@ -234,13 +235,16 @@ TEST_F(FileUtilsTestSuite, ExtractZipDataTest) { EXPECT_EQ(status, CELIX_SUCCESS); EXPECT_TRUE(celix_utils_fileExists(file1)); - auto* props = celix_properties_load(file1); + celix_properties_t* props = nullptr; + status = celix_properties_load(file1, 0, &props); + EXPECT_EQ(status, CELIX_SUCCESS); EXPECT_NE(props, nullptr); EXPECT_EQ(celix_properties_getAsLong(props, "level", 0), 1); celix_properties_destroy(props); EXPECT_TRUE(celix_utils_fileExists(file2)); - props = celix_properties_load(file2); + status = celix_properties_load(file2, 0, &props); + EXPECT_EQ(status, CELIX_SUCCESS); EXPECT_NE(props, nullptr); EXPECT_EQ(celix_properties_getAsLong(props, "level", 0), 2); celix_properties_destroy(props); @@ -262,13 +266,15 @@ TEST_F(FileUtilsTestSuite, ExtractZipDataTest) { EXPECT_EQ(status, CELIX_SUCCESS); EXPECT_TRUE(celix_utils_fileExists(file1)); - auto* props = celix_properties_load(file1); + celix_properties_t* props = nullptr; + EXPECT_EQ(CELIX_SUCCESS, celix_properties_load(file1, 0, &props)); EXPECT_NE(props, nullptr); EXPECT_EQ(celix_properties_getAsLong(props, "level", 0), 1); celix_properties_destroy(props); EXPECT_TRUE(celix_utils_fileExists(file2)); - props = celix_properties_load(file2); + props = nullptr; + EXPECT_EQ(CELIX_SUCCESS, celix_properties_load(file2, 0, &props)); EXPECT_NE(props, nullptr); EXPECT_EQ(celix_properties_getAsLong(props, "level", 0), 2); celix_properties_destroy(props); diff --git a/libs/utils/gtest/src/PropertiesEncodingErrorInjectionTestSuite.cc b/libs/utils/gtest/src/PropertiesEncodingErrorInjectionTestSuite.cc index 9a5c15f7e..1ec9e7dd3 100644 --- a/libs/utils/gtest/src/PropertiesEncodingErrorInjectionTestSuite.cc +++ b/libs/utils/gtest/src/PropertiesEncodingErrorInjectionTestSuite.cc @@ -254,11 +254,11 @@ TEST_F(PropertiesEncodingErrorInjectionTestSuite, LoadErrorTest) { const char* json = R"({"key":"value"})"; //When an error injected is prepared for fmemopen() from loadFromString2 - celix_ei_expect_fmemopen((void*)celix_properties_loadFromString2, 0, nullptr); + celix_ei_expect_fmemopen((void*)celix_properties_loadFromString, 0, nullptr); //When I call celix_properties_loadFromString celix_properties_t* props; - auto status = celix_properties_loadFromString2(json, 0, &props); + auto status = celix_properties_loadFromString(json, 0, &props); //Then I expect an error EXPECT_EQ(ENOMEM, status); @@ -273,20 +273,20 @@ TEST_F(PropertiesEncodingErrorInjectionTestSuite, DecodeErrorTest) { const char* json = R"({"key":"value", "object": {"key":"value"}})"; //When an error injected is prepared for celix_properties_create()->malloc() from celix_properties_loadFromString2 - celix_ei_expect_malloc((void*)celix_properties_loadFromString2, 3, nullptr); + celix_ei_expect_malloc((void*)celix_properties_loadFromString, 3, nullptr); //When I call celix_properties_loadFromString celix_properties_t* props; - auto status = celix_properties_loadFromString2(json, 0, &props); + auto status = celix_properties_loadFromString(json, 0, &props); //Then I expect an error EXPECT_EQ(ENOMEM, status); //When an error injected is prepared for celix_utils_writeOrCreateString() from celix_properties_loadFromString2 - celix_ei_expect_celix_utils_writeOrCreateString((void*)celix_properties_loadFromString2, 3, nullptr); + celix_ei_expect_celix_utils_writeOrCreateString((void*)celix_properties_loadFromString, 3, nullptr); //When I call celix_properties_loadFromString - status = celix_properties_loadFromString2(json, 0, &props); + status = celix_properties_loadFromString(json, 0, &props); //Then I expect an error EXPECT_EQ(ENOMEM, status); @@ -301,20 +301,20 @@ TEST_F(PropertiesEncodingErrorInjectionTestSuite, DecodeArrayErrorTest) { const char* json = R"({"key":["value1", "value2"]})"; // When an error injected is prepared for celix_arrayList_createWithOptions() from celix_properties_loadFromString2 - celix_ei_expect_celix_arrayList_createWithOptions((void*)celix_properties_loadFromString2, 4, nullptr); + celix_ei_expect_celix_arrayList_createWithOptions((void*)celix_properties_loadFromString, 4, nullptr); //When I call celix_properties_loadFromString celix_properties_t* props; - auto status = celix_properties_loadFromString2(json, 0, &props); + auto status = celix_properties_loadFromString(json, 0, &props); //Then I expect an error EXPECT_EQ(ENOMEM, status); // When an error injected is prepared for celix_arrayList_addString() from celix_properties_loadFromString2 - celix_ei_expect_celix_arrayList_addString((void*)celix_properties_loadFromString2, 4, ENOMEM); + celix_ei_expect_celix_arrayList_addString((void*)celix_properties_loadFromString, 4, ENOMEM); //When I call celix_properties_loadFromString - status = celix_properties_loadFromString2(json, 0, &props); + status = celix_properties_loadFromString(json, 0, &props); //Then I expect an error EXPECT_EQ(ENOMEM, status); @@ -330,11 +330,11 @@ TEST_F(PropertiesEncodingErrorInjectionTestSuite, DecodeVersionErrorTest) { const char* json = R"({"key":"version<1.2.3.qualifier>"})"; // When an error injected is prepared for celix_utils_writeOrCreateString() from celix_properties_loadFromString2 - celix_ei_expect_celix_utils_writeOrCreateString((void*)celix_properties_loadFromString2, 4, nullptr); + celix_ei_expect_celix_utils_writeOrCreateString((void*)celix_properties_loadFromString, 4, nullptr); // And I call celix_properties_loadFromString celix_properties_t* props; - auto status = celix_properties_loadFromString2(json, 0, &props); + auto status = celix_properties_loadFromString(json, 0, &props); // Then I expect an error EXPECT_EQ(ENOMEM, status); diff --git a/libs/utils/gtest/src/PropertiesEncodingTestSuite.cc b/libs/utils/gtest/src/PropertiesEncodingTestSuite.cc index fedec728a..a1eceb4aa 100644 --- a/libs/utils/gtest/src/PropertiesEncodingTestSuite.cc +++ b/libs/utils/gtest/src/PropertiesEncodingTestSuite.cc @@ -241,7 +241,7 @@ TEST_F(PropertiesSerializationTestSuite, SaveEmptyKeyTest) { ASSERT_EQ(CELIX_SUCCESS, status); celix_autoptr(celix_properties_t) prop2 = nullptr; - status = celix_properties_loadFromString2(output1, 0, &prop2); + status = celix_properties_loadFromString(output1, 0, &prop2); ASSERT_EQ(CELIX_SUCCESS, status); ASSERT_TRUE(celix_properties_equals(props, prop2)); @@ -524,7 +524,7 @@ TEST_F(PropertiesSerializationTestSuite, LoadEmptyPropertiesTest) { //When loading the properties from the stream celix_autoptr(celix_properties_t) props = nullptr; - auto status = celix_properties_loadFromString2(json, 0, &props); + auto status = celix_properties_loadFromString(json, 0, &props); ASSERT_EQ(CELIX_SUCCESS, status); //Then the properties object is empty @@ -681,7 +681,7 @@ TEST_F(PropertiesSerializationTestSuite, LoadPropertiesWithEmptyArrayTest) { //When loading the properties from string celix_autoptr(celix_properties_t) props = nullptr; - auto status = celix_properties_loadFromString2(inputJSON, 0, &props); + auto status = celix_properties_loadFromString(inputJSON, 0, &props); //Then loading succeeds ASSERT_EQ(CELIX_SUCCESS, status); @@ -691,7 +691,7 @@ TEST_F(PropertiesSerializationTestSuite, LoadPropertiesWithEmptyArrayTest) { //When loading the properties from string with a strict flag celix_properties_t* props2; - status = celix_properties_loadFromString2(inputJSON, CELIX_PROPERTIES_DECODE_ERROR_ON_EMPTY_ARRAYS, &props2); + status = celix_properties_loadFromString(inputJSON, CELIX_PROPERTIES_DECODE_ERROR_ON_EMPTY_ARRAYS, &props2); //Then loading fails, because the empty array generates an error ASSERT_EQ(CELIX_ILLEGAL_ARGUMENT, status); @@ -746,7 +746,7 @@ TEST_F(PropertiesSerializationTestSuite, LoadPropertiesWithDuplicatesTest) { // When loading the properties from a string. celix_autoptr(celix_properties_t) props = nullptr; - auto status = celix_properties_loadFromString2(jsonInput, 0, &props); + auto status = celix_properties_loadFromString(jsonInput, 0, &props); // Then loading succeeds ASSERT_EQ(CELIX_SUCCESS, status); @@ -757,7 +757,7 @@ TEST_F(PropertiesSerializationTestSuite, LoadPropertiesWithDuplicatesTest) { // When decoding the properties from the stream using a flog that does not allow duplicates celix_properties_t* props2; - status = celix_properties_loadFromString2(jsonInput, CELIX_PROPERTIES_DECODE_ERROR_ON_DUPLICATES, &props2); + status = celix_properties_loadFromString(jsonInput, CELIX_PROPERTIES_DECODE_ERROR_ON_DUPLICATES, &props2); // Then loading fails, because of a duplicate key EXPECT_EQ(CELIX_ILLEGAL_ARGUMENT, status); @@ -793,7 +793,7 @@ TEST_F(PropertiesSerializationTestSuite, LoadPropertiesEscapedDotsTest) { // When loading the properties from a string. celix_autoptr(celix_properties_t) props; - auto status = celix_properties_loadFromString2(jsonInput, 0, &props); + auto status = celix_properties_loadFromString(jsonInput, 0, &props); // Then loading succeeds ASSERT_EQ(CELIX_SUCCESS, status); @@ -809,7 +809,7 @@ TEST_F(PropertiesSerializationTestSuite, LoadPropertiesEscapedDotsTest) { // When decoding the properties from a string using a flag that allows duplicates celix_properties_t* props2; - status = celix_properties_loadFromString2(jsonInput, CELIX_PROPERTIES_DECODE_ERROR_ON_DUPLICATES, &props2); + status = celix_properties_loadFromString(jsonInput, CELIX_PROPERTIES_DECODE_ERROR_ON_DUPLICATES, &props2); // Then loading fails, because of a duplicate key EXPECT_EQ(CELIX_ILLEGAL_ARGUMENT, status); @@ -820,7 +820,7 @@ TEST_F(PropertiesSerializationTestSuite, LoadPropertiesEscapedDotsTest) { // When decoding the properties from a string using a flag that allows collisions celix_properties_t* props3; - status = celix_properties_loadFromString2(jsonInput, CELIX_PROPERTIES_DECODE_ERROR_ON_COLLISIONS, &props3); + status = celix_properties_loadFromString(jsonInput, CELIX_PROPERTIES_DECODE_ERROR_ON_COLLISIONS, &props3); // Then loading fails, because of a collision EXPECT_EQ(CELIX_ILLEGAL_ARGUMENT, status); @@ -889,7 +889,7 @@ TEST_F(PropertiesSerializationTestSuite, LoadPropertiesWithUnsupportedArrayTypes for (auto& invalidArray : invalidArrays) { // When loading the properties from the string celix_autoptr(celix_properties_t) props = nullptr; - auto status = celix_properties_loadFromString2(invalidArray, 0, &props); + auto status = celix_properties_loadFromString(invalidArray, 0, &props); // Then decoding succeeds, because strict is disabled ASSERT_EQ(CELIX_SUCCESS, status); @@ -903,7 +903,7 @@ TEST_F(PropertiesSerializationTestSuite, LoadPropertiesWithUnsupportedArrayTypes for (auto& invalidArray : invalidArrays) { // When loading the properties from the string celix_autoptr(celix_properties_t) props = nullptr; - auto status = celix_properties_loadFromString2(invalidArray, CELIX_PROPERTIES_DECODE_STRICT, &props); + auto status = celix_properties_loadFromString(invalidArray, CELIX_PROPERTIES_DECODE_STRICT, &props); // Then decoding fails EXPECT_EQ(CELIX_ILLEGAL_ARGUMENT, status); @@ -914,8 +914,8 @@ TEST_F(PropertiesSerializationTestSuite, LoadPropertiesWithUnsupportedArrayTypes // When loading the properties from the CELIX_PROPERTIES_DECODE_ERROR_ON_UNSUPPORTED_ARRAYS flag celix_properties_t* props2; - status = celix_properties_loadFromString2( - invalidArray, CELIX_PROPERTIES_DECODE_ERROR_ON_UNSUPPORTED_ARRAYS, &props2); + status = + celix_properties_loadFromString(invalidArray, CELIX_PROPERTIES_DECODE_ERROR_ON_UNSUPPORTED_ARRAYS, &props2); // Then decoding fails EXPECT_EQ(CELIX_ILLEGAL_ARGUMENT, status); @@ -965,7 +965,7 @@ TEST_F(PropertiesSerializationTestSuite, LoadPropertiesWithInvalidVersionsTest) // When loading the properties from the stream celix_autoptr(celix_properties_t) props = nullptr; - auto status = celix_properties_loadFromString2(jsonInput, 0, &props); + auto status = celix_properties_loadFromString(jsonInput, 0, &props); // Then loading fails ASSERT_EQ(CELIX_ILLEGAL_ARGUMENT, status); @@ -979,7 +979,7 @@ TEST_F(PropertiesSerializationTestSuite, LoadPropertiesWithInvalidVersionsTest) R"( {"key1":"version<1.2.3", "key2":"version1.2.3>", "key3":"ver<1.2.3>}", "key4":"celix_version<1.2.3>"} )"; // When loading the properties from the stream - status = celix_properties_loadFromString2(jsonInput, 0, &props); + status = celix_properties_loadFromString(jsonInput, 0, &props); // Then loading succeeds ASSERT_EQ(CELIX_SUCCESS, status); @@ -995,7 +995,7 @@ TEST_F(PropertiesSerializationTestSuite, LoadWithInvalidStreamTest) { celix_properties_t* dummyProps = nullptr; // Loading properties with invalid stream will fail - auto status = celix_properties_load2("non_existing_file.json", 0, &dummyProps); + auto status = celix_properties_load("non_existing_file.json", 0, &dummyProps); EXPECT_EQ(CELIX_FILE_IO_EXCEPTION, status); EXPECT_EQ(1, celix_err_getErrorCount()); @@ -1084,7 +1084,7 @@ TEST_F(PropertiesSerializationTestSuite, SaveAndLoadFlatProperties) { // When loading the properties from the properties_test.json file celix_autoptr(celix_properties_t) loadedProps = nullptr; - status = celix_properties_load2(filename, 0, &loadedProps); + status = celix_properties_load(filename, 0, &loadedProps); // Then loading succeeds ASSERT_EQ(CELIX_SUCCESS, status); diff --git a/libs/utils/gtest/src/PropertiesErrorInjectionTestSuite.cc b/libs/utils/gtest/src/PropertiesErrorInjectionTestSuite.cc index e7916ea38..2ff3ff66c 100644 --- a/libs/utils/gtest/src/PropertiesErrorInjectionTestSuite.cc +++ b/libs/utils/gtest/src/PropertiesErrorInjectionTestSuite.cc @@ -50,14 +50,8 @@ class PropertiesErrorInjectionTestSuite : public ::testing::Test { celix_ei_expect_celix_stringHashMap_createWithOptions(nullptr, 0, nullptr); celix_ei_expect_celix_arrayList_copy(nullptr, 0, nullptr); celix_ei_expect_celix_utils_strdup(nullptr, 0, nullptr); - celix_ei_expect_fopen(nullptr, 0, nullptr); - celix_ei_expect_fputc(nullptr, 0, 0); - celix_ei_expect_fseek(nullptr, 0, 0); - celix_ei_expect_ftell(nullptr, 0, 0); - celix_ei_expect_celix_utils_strdup(nullptr, 0, nullptr); celix_ei_expect_celix_stringHashMap_put(nullptr, 0, 0); celix_ei_expect_celix_version_copy(nullptr, 0, nullptr); - celix_ei_expect_celix_arrayList_createWithOptions(nullptr, 0, nullptr); celix_ei_expect_celix_arrayList_copy(nullptr, 0, nullptr); } @@ -176,116 +170,6 @@ TEST_F(PropertiesErrorInjectionTestSuite, SetFailureTest) { ASSERT_THROW(cxxProps.set("key", "value"), std::bad_alloc); } -TEST_F(PropertiesErrorInjectionTestSuite, StoreFailureTest) { - // C API - // Given a celix properties object - celix_autoptr(celix_properties_t) props = celix_properties_create(); - celix_properties_set(props, "key", "value"); - - // When a fopen error injection is set for celix_properties_store (during fopen) - celix_ei_expect_fopen((void*)celix_properties_store, 0, nullptr); - // Then the celix_properties_store call fails - auto status = celix_properties_store(props, "file", nullptr); - ASSERT_EQ(status, CELIX_FILE_IO_EXCEPTION); - // And a celix err msg is set - ASSERT_EQ(1, celix_err_getErrorCount()); - celix_err_resetErrors(); - - // When a fputc error injection is set for celix_properties_store (during fputc) - celix_ei_expect_fputc((void*)celix_properties_store, 0, EOF); - // Then the celix_properties_store call fails - status = celix_properties_store(props, "file", nullptr); - ASSERT_EQ(status, CELIX_FILE_IO_EXCEPTION); - // And a celix err msg is set - ASSERT_EQ(1, celix_err_getErrorCount()); - celix_err_resetErrors(); - - // C++ API - // Given a C++ celix properties object. - auto cxxProps = celix::Properties{}; - cxxProps.set("key", "value"); - - // When a fopen error injection is set for celix_properties_store (during fopen) - celix_ei_expect_fopen((void*)celix_properties_store, 0, nullptr); - // Then the Properties:store throws a celix::IOException exception - EXPECT_THROW(cxxProps.store("file"), celix::IOException); - // And a celix err msg is set - ASSERT_EQ(1, celix_err_getErrorCount()); - celix_err_resetErrors(); -} - -TEST_F(PropertiesErrorInjectionTestSuite, LoadFailureTest) { - // C API - // Given a fmemstream buffer with a properties file - const char* content = "key=value\n"; - auto* memStream = fmemopen((void*)content, strlen(content), "r"); - - // When a fopen error injection is set for celix_properties_load (during fopen) - celix_ei_expect_fopen((void*)celix_properties_load, 0, nullptr); - // Then the celix_properties_load call fails - auto props = celix_properties_load("file"); - ASSERT_EQ(nullptr, props); - // And a celix err msg is set - ASSERT_EQ(1, celix_err_getErrorCount()); - celix_err_resetErrors(); - - // When a malloc error injection is set for celix_properties_loadWithStream (during properties create) - celix_ei_expect_malloc((void*)celix_properties_create, 0, nullptr); - // Then the celix_properties_loadWithStream call fails - props = celix_properties_loadWithStream(memStream); - ASSERT_EQ(nullptr, props); - // And a celix err msg is set - ASSERT_EQ(1, celix_err_getErrorCount()); - celix_err_resetErrors(); - - // When a fseek error injection is set for celix_properties_loadWithStream - celix_ei_expect_fseek((void*)celix_properties_loadWithStream, 0, -1); - // Then the celix_properties_loadWithStream call fails - props = celix_properties_loadWithStream(memStream); - ASSERT_EQ(nullptr, props); - // And a celix err msg is set - ASSERT_EQ(1, celix_err_getErrorCount()); - celix_err_resetErrors(); - - // When a fseek error injection is set for celix_properties_loadWithStream, ordinal 2 - celix_ei_expect_fseek((void*)celix_properties_loadWithStream, 0, -1, 2); - // Then the celix_properties_loadWithStream call fails - props = celix_properties_loadWithStream(memStream); - ASSERT_EQ(nullptr, props); - // And a celix err msg is set - ASSERT_EQ(1, celix_err_getErrorCount()); - celix_err_resetErrors(); - - // When a ftell error injection is set for celix_properties_loadWithStream - celix_ei_expect_ftell((void*)celix_properties_loadWithStream, 0, -1); - // Then the celix_properties_loadWithStream call fails - props = celix_properties_loadWithStream(memStream); - ASSERT_EQ(nullptr, props); - // And a celix err msg is set - ASSERT_EQ(1, celix_err_getErrorCount()); - celix_err_resetErrors(); - - // When a malloc error injection is set for celix_properties_loadWithStream - celix_ei_expect_malloc((void*)celix_properties_loadWithStream, 0, nullptr); - // Then the celix_properties_loadWithStream call fails - props = celix_properties_loadWithStream(memStream); - ASSERT_EQ(nullptr, props); - // And a celix err msg is set - ASSERT_EQ(1, celix_err_getErrorCount()); - celix_err_resetErrors(); - - //C++ API - // When a fopen error injection is set for celix_properties_load (during fopen) - celix_ei_expect_fopen((void*)celix_properties_load, 0, nullptr); - // Then the celix::Properties::load call throws a celix::IOException exception - EXPECT_THROW(celix::Properties::load("file"), celix::IOException); - // And a celix err msg is set - ASSERT_EQ(1, celix_err_getErrorCount()); - celix_err_resetErrors(); - - fclose(memStream); -} - TEST_F(PropertiesErrorInjectionTestSuite, GetAsVersionWithVersionCopyFailedTest) { //Given a properties set with a version celix_autoptr(celix_properties_t) props = celix_properties_create(); @@ -428,17 +312,6 @@ TEST_F(PropertiesErrorInjectionTestSuite, AssignFailureTest) { celix_err_resetErrors(); } -TEST_F(PropertiesErrorInjectionTestSuite, LoadFromStringFailureTest) { - // When a strdup error injection is set for celix_properties_loadFromString (during strdup) - celix_ei_expect_celix_utils_strdup((void*)celix_properties_loadFromString, 0, nullptr); - // Then the celix_properties_loadFromString call fails - auto props = celix_properties_loadFromString("key=value"); - ASSERT_EQ(nullptr, props); - // And a celix err msg is set - ASSERT_EQ(1, celix_err_getErrorCount()); - celix_err_resetErrors(); -} - TEST_F(PropertiesErrorInjectionTestSuite, SetVersionFailureTest) { // Given a celix properties object celix_autoptr(celix_properties_t) props = celix_properties_create(); diff --git a/libs/utils/gtest/src/PropertiesTestSuite.cc b/libs/utils/gtest/src/PropertiesTestSuite.cc index f44e0b077..391488c4c 100644 --- a/libs/utils/gtest/src/PropertiesTestSuite.cc +++ b/libs/utils/gtest/src/PropertiesTestSuite.cc @@ -54,69 +54,6 @@ TEST_F(PropertiesTestSuite, CreateTest) { celix_properties_destroy(properties); } -TEST_F(PropertiesTestSuite, LoadTest) { - char propertiesFile[] = "resources-test/properties.txt"; - auto* properties = celix_properties_load(propertiesFile); - EXPECT_EQ(4, celix_properties_size(properties)); - - const char keyA[] = "a"; - const char *valueA = celix_properties_get(properties, keyA, nullptr); - EXPECT_STREQ("b", valueA); - - const char keyNiceA[] = "nice_a"; - const char *valueNiceA = celix_properties_get(properties, keyNiceA, nullptr); - EXPECT_STREQ("nice_b", valueNiceA); - - const char keyB[] = "b"; - const char *valueB = celix_properties_get(properties, keyB, nullptr); - EXPECT_STREQ("c \t d", valueB); - - celix_properties_destroy(properties); -} - -TEST_F(PropertiesTestSuite, LoadFromStringTest) { - const char* string = "key1=value1\nkey2=value2"; - auto* props = celix_properties_loadFromString(string); - EXPECT_EQ(2, celix_properties_size(props)); - EXPECT_STREQ("value1", celix_properties_get(props, "key1", "")); - EXPECT_STREQ("value2", celix_properties_get(props, "key2", "")); - celix_properties_destroy(props); -} - - -TEST_F(PropertiesTestSuite, StoreTest) { - const char* propertiesFile = "resources-test/properties_out.txt"; - celix_autoptr(celix_properties_t) properties = celix_properties_create(); - celix_properties_set(properties, "keyA", "valueA"); - celix_properties_set(properties, "keyB", "valueB"); - celix_properties_store(properties, propertiesFile, nullptr); - - celix_autoptr(celix_properties_t) properties2 = celix_properties_load(propertiesFile); - EXPECT_EQ(celix_properties_size(properties), celix_properties_size(properties2)); - EXPECT_STREQ(celix_properties_get(properties, "keyA", ""), celix_properties_get(properties2, "keyA", "")); - EXPECT_STREQ(celix_properties_get(properties, "keyB", ""), celix_properties_get(properties2, "keyB", "")); -} - -TEST_F(PropertiesTestSuite, StoreWithHeaderTest) { - const char* propertiesFile = "resources-test/properties_with_header_out.txt"; - celix_autoptr(celix_properties_t) properties = celix_properties_create(); - celix_properties_set(properties, "keyA", "valueA"); - celix_properties_set(properties, "keyB", "valueB"); - celix_properties_store(properties, propertiesFile, "header"); - - celix_autoptr(celix_properties_t) properties2 = celix_properties_load(propertiesFile); - EXPECT_EQ(celix_properties_size(properties), celix_properties_size(properties2)); - EXPECT_STREQ(celix_properties_get(properties, "keyA", ""), celix_properties_get(properties2, "keyA", "")); - EXPECT_STREQ(celix_properties_get(properties, "keyB", ""), celix_properties_get(properties2, "keyB", "")); - - //check if provided header text is present in file - FILE *f = fopen(propertiesFile, "r"); - char line[1024]; - fgets(line, sizeof(line), f); - EXPECT_STREQ("#header\n", line); - fclose(f); -} - TEST_F(PropertiesTestSuite, GetAsLongTest) { celix_properties_t *props = celix_properties_create(); celix_properties_set(props, "t1", "42"); @@ -662,11 +599,6 @@ TEST_F(PropertiesTestSuite, PropertiesAutoCleanupTest) { celix_autoptr(celix_properties_t) props = celix_properties_create(); } -TEST_F(PropertiesTestSuite, NullArgumentsTest) { - auto props = celix_properties_loadWithStream(nullptr); - EXPECT_EQ(nullptr, props); -} - TEST_F(PropertiesTestSuite, PropertiesEqualsTest) { EXPECT_TRUE(celix_properties_equals(nullptr, nullptr)); diff --git a/libs/utils/gtest/src/VersionTestSuite.cc b/libs/utils/gtest/src/VersionTestSuite.cc index 736561e80..4406941db 100644 --- a/libs/utils/gtest/src/VersionTestSuite.cc +++ b/libs/utils/gtest/src/VersionTestSuite.cc @@ -279,18 +279,18 @@ TEST_F(VersionTestSuite, ParseTest) { parseStatus = celix_version_parse(largeLong.c_str(), &result); EXPECT_EQ(CELIX_ILLEGAL_ARGUMENT, parseStatus); EXPECT_EQ(nullptr, result); - EXPECT_STREQ("Invalid version component(0)", celix_err_popLastError()); + EXPECT_TRUE(strstr(celix_err_popLastError(), "Invalid version part 0.")); auto largeInteger = std::to_string(std::numeric_limits::max()); parseStatus = celix_version_parse(largeInteger.c_str(), &result); EXPECT_EQ(CELIX_ILLEGAL_ARGUMENT, parseStatus); EXPECT_EQ(nullptr, result); - EXPECT_STREQ("Invalid version component(0)", celix_err_popLastError()); + EXPECT_TRUE(strstr(celix_err_popLastError(), "Invalid version part 0.")); parseStatus = celix_version_parse("", &result); EXPECT_EQ(CELIX_ILLEGAL_ARGUMENT, parseStatus); EXPECT_EQ(nullptr, result); - EXPECT_STREQ("Invalid version component(0)", celix_err_popLastError()); + EXPECT_TRUE(strstr(celix_err_popLastError(), "Invalid version part 0.")); parseStatus = celix_version_parse(nullptr, &result); EXPECT_EQ(CELIX_ILLEGAL_ARGUMENT, parseStatus); @@ -299,22 +299,27 @@ TEST_F(VersionTestSuite, ParseTest) { parseStatus = celix_version_parse("invalid", &result); EXPECT_EQ(CELIX_ILLEGAL_ARGUMENT, parseStatus); EXPECT_EQ(nullptr, result); - EXPECT_STREQ("Invalid version component(0)", celix_err_popLastError()); + EXPECT_TRUE(strstr(celix_err_popLastError(), "Invalid version part 0.")); parseStatus = celix_version_parse("-1", &result); EXPECT_EQ(CELIX_ILLEGAL_ARGUMENT, parseStatus); EXPECT_EQ(nullptr, result); - EXPECT_STREQ("Invalid version component(0)", celix_err_popLastError()); + EXPECT_TRUE(strstr(celix_err_popLastError(), "Invalid version part 0.")); parseStatus = celix_version_parse("1.-2", &result); EXPECT_EQ(CELIX_ILLEGAL_ARGUMENT, parseStatus); EXPECT_EQ(nullptr, result); - EXPECT_STREQ("Invalid version component(1)", celix_err_popLastError()); + EXPECT_TRUE(strstr(celix_err_popLastError(), "Invalid version part 1.")); parseStatus = celix_version_parse("1.2.-3", &result); EXPECT_EQ(CELIX_ILLEGAL_ARGUMENT, parseStatus); EXPECT_EQ(nullptr, result); - EXPECT_STREQ("Invalid version component(2)", celix_err_popLastError()); + EXPECT_TRUE(strstr(celix_err_popLastError(), "Invalid version part 2.")); + + parseStatus = celix_version_tryParse("1.2.-3", &result); + EXPECT_EQ(CELIX_ILLEGAL_ARGUMENT, parseStatus); + EXPECT_EQ(nullptr, result); + EXPECT_EQ(0, celix_err_getErrorCount()); } TEST_F(VersionTestSuite, HashTest) { diff --git a/libs/utils/include/celix/Properties.h b/libs/utils/include/celix/Properties.h index ee71925ea..9389d0950 100644 --- a/libs/utils/include/celix/Properties.h +++ b/libs/utils/include/celix/Properties.h @@ -932,21 +932,6 @@ namespace celix { return result; } - /** - * @brief Store the property set to the given file path. - * - * This function writes the properties in the given set to the specified file path in a format suitable - * for loading with the load() function. - * If a non-empty header string is provided, it will be written as a comment at the beginning of the file. - * - * @param[in] file The file to store the properties to. - * @param[in] header An optional (single line) header string to include as a comment at the beginning of the file. - * @throws celix::IOException If an error occurs while writing to the file. - */ - void store(const std::string& path, const std::string& header = {}) const { - storeTo(path.data(), header.empty() ? nullptr : header.data()); - } - /** * @brief Enum class for encoding flags used in Celix properties JSON encoding. * @@ -1044,16 +1029,6 @@ namespace celix { Strict = CELIX_PROPERTIES_DECODE_STRICT /**< If set, decoding will fail if there are any errors. */ }; - /** - * @brief Loads properties from the file at the given path. - * @param[in] path The path to the file containing the properties. - * @return A new Properties object containing the properties from the file. - * @throws celix::IOException If the file cannot be opened or read. - * @throws celix::IllegalArgumentException if the provided input cannot be decoded to a properties object. - * @throws std::bad_alloc If there was not enough memory to load the properties. - */ - static Properties load(const std::string& path) { return loadFrom(path.data()); } - /** * @brief Load a Properties object from a file. * @@ -1074,7 +1049,7 @@ namespace celix { */ static Properties load2(const std::string& filename, DecodeFlags decodeFlags = DecodeFlags::None) { celix_properties_t* props; - auto status = celix_properties_load2(filename.c_str(), static_cast(decodeFlags), &props); + auto status = celix_properties_load(filename.c_str(), static_cast(decodeFlags), &props); if (status == ENOMEM) { throw std::bad_alloc(); } else if (status != CELIX_SUCCESS) { @@ -1100,7 +1075,7 @@ namespace celix { */ static Properties loadFromString(const std::string& input, DecodeFlags decodeFlags = DecodeFlags::None) { celix_properties_t* props; - auto status = celix_properties_loadFromString2(input.c_str(), static_cast(decodeFlags), &props); + auto status = celix_properties_loadFromString(input.c_str(), static_cast(decodeFlags), &props); if (status == ENOMEM) { throw std::bad_alloc(); } else if (status != CELIX_SUCCESS) { @@ -1153,21 +1128,6 @@ namespace celix { } } - static celix::Properties loadFrom(const char* path) { - auto* cProps = celix_properties_load(path); - if (cProps) { - return celix::Properties::own(cProps); - } - throw celix::IOException{"Cannot load celix::Properties from path " + std::string{path}}; - } - - void storeTo(const char* path, const char* header) const { - auto status = celix_properties_store(cProps.get(), path, header); - if (status != CELIX_SUCCESS) { - throw celix::IOException{"Cannot store celix::Properties to " + std::string{path}}; - } - } - template std::vector convertToVector(const celix_array_list_t* list, const std::vector& defaultValue, T (*get)(const celix_array_list_t*, int index)) const { if (list) { diff --git a/libs/utils/include/celix_properties.h b/libs/utils/include/celix_properties.h index f49d4628b..b145fc72d 100644 --- a/libs/utils/include/celix_properties.h +++ b/libs/utils/include/celix_properties.h @@ -129,57 +129,6 @@ CELIX_UTILS_EXPORT void celix_properties_destroy(celix_properties_t* properties) CELIX_DEFINE_AUTOPTR_CLEANUP_FUNC(celix_properties_t, celix_properties_destroy) -/** - * @brief Load properties from a file. - * - * If the return status is an error, an error message is logged to celix_err. - * - * @param[in] filename The name of the file to load properties from. - * @return A property set containing the properties from the file. - * @retval NULL If an error occurred (e.g. file not found). - */ -CELIX_UTILS_EXPORT celix_properties_t* celix_properties_load(const char* filename); - -/** - * @brief Load properties from a stream. - * - * If the return status is an error, an error message is logged to celix_err. - * - * @param[in,out] stream The stream to load properties from. - * @return A property set containing the properties from the stream. - * @retval NULL If an error occurred (e.g. invalid format). - */ -CELIX_UTILS_EXPORT celix_properties_t* celix_properties_loadWithStream(FILE* stream); - -/** - * @brief Load properties from a string. - * - * If the return status is an error, an error message is logged to celix_err. - * - * @param[in] input The string to load properties from. - * @return A property set containing the properties from the string. - * @retval NULL If an error occurred (e.g. invalid format). - */ -CELIX_UTILS_EXPORT celix_properties_t* celix_properties_loadFromString(const char* input); - -/** - * @brief Store properties to a file. - * - * @note Properties values are always stored as string values, regardless of their actual underlining types. - * - * If the return status is an error, an error message is logged to celix_err. - * - * @param[in] properties The property set to store. - * @param[in] file The name of the file to store the properties to. - * @param[in] header An optional - single line - header to write to the file before the properties. - * Will be prefix with a '#' character. - * @return CELIX_SUCCESS if the operation was successful, CELIX_FILE_IO_EXCEPTION if there was an error writing to the - * file. - */ -CELIX_UTILS_EXPORT celix_status_t celix_properties_store(celix_properties_t* properties, - const char* file, - const char* header); - /** * @brief Get the entry for a given key in a property set. * @@ -1259,7 +1208,7 @@ CELIX_UTILS_EXPORT celix_status_t celix_properties_loadFromStream(FILE* stream, * decoded to a properties object and ENOMEM if there was not enough memory. CELIX_FILE_IO_EXCEPTION if the file * could not be opened. */ -CELIX_UTILS_EXPORT celix_status_t celix_properties_load2(const char* filename, +CELIX_UTILS_EXPORT celix_status_t celix_properties_load(const char* filename, int decodeFlags, celix_properties_t** out); @@ -1283,7 +1232,7 @@ CELIX_UTILS_EXPORT celix_status_t celix_properties_load2(const char* filename, * @return CELIX_SUCCESS if the operation was successful, CELIX_ILLEGAL_ARGUMENT if the provided input cannot be * decoded to a properties object and ENOMEM if there was not enough memory. */ -CELIX_UTILS_EXPORT celix_status_t celix_properties_loadFromString2(const char* input, +CELIX_UTILS_EXPORT celix_status_t celix_properties_loadFromString(const char* input, int decodeFlags, celix_properties_t** out); diff --git a/libs/utils/include/celix_stdio_cleanup.h b/libs/utils/include/celix_stdio_cleanup.h index 43cbff16b..32c4868a7 100644 --- a/libs/utils/include/celix_stdio_cleanup.h +++ b/libs/utils/include/celix_stdio_cleanup.h @@ -25,11 +25,14 @@ extern "C" { #endif #include +#include #include "celix_cleanup.h" CELIX_DEFINE_AUTOPTR_CLEANUP_FUNC(FILE, fclose) +CELIX_DEFINE_AUTOPTR_CLEANUP_FUNC(DIR, closedir) + #ifdef __cplusplus } #endif diff --git a/libs/utils/include/celix_threads.h b/libs/utils/include/celix_threads.h index 19c585f3b..45c3111f1 100644 --- a/libs/utils/include/celix_threads.h +++ b/libs/utils/include/celix_threads.h @@ -22,6 +22,7 @@ #include #include +#include #include "celix_cleanup.h" #include "celix_errno.h" @@ -141,6 +142,7 @@ static CELIX_UNUSED inline celix_mutex_lock_guard_t celixMutexLockGuard_init(cel static CELIX_UNUSED inline void celixMutexLockGuard_deinit(celix_mutex_lock_guard_t* guard) { if (guard->mutex) { celixThreadMutex_unlock(guard->mutex); + guard->mutex = NULL; } } @@ -215,6 +217,7 @@ static CELIX_UNUSED inline celix_rwlock_wlock_guard_t celixRwlockWlockGuard_init static CELIX_UNUSED inline void celixRwlockWlockGuard_deinit(celix_rwlock_wlock_guard_t* guard) { if (guard->lock) { celixThreadRwlock_unlock(guard->lock); + guard->lock = NULL; } } @@ -262,6 +265,7 @@ static CELIX_UNUSED inline celix_rwlock_rlock_guard_t celixRwlockRlockGuard_init static CELIX_UNUSED inline void celixRwlockRlockGuard_deinit(celix_rwlock_rlock_guard_t* guard) { if (guard->lock) { celixThreadRwlock_unlock(guard->lock); + guard->lock = NULL; } } diff --git a/libs/utils/include/celix_version.h b/libs/utils/include/celix_version.h index 4e4a87adf..7c36b39a1 100644 --- a/libs/utils/include/celix_version.h +++ b/libs/utils/include/celix_version.h @@ -126,6 +126,18 @@ CELIX_UTILS_EXPORT celix_version_t* celix_version_createVersionFromString(const */ CELIX_UTILS_EXPORT celix_status_t celix_version_parse(const char *versionStr, celix_version_t** version); +/** + * @brief Try to parse a version string into a version object. + * Identical to celix_version_parse, but does not log an error if the version string is invalid (does log if memory + * could not be allocated). + * + * @param[in] versionStr The version string to parse. + * @param[out] version The parsed version object. + * @return CELIX_SUCCESS if the version string was parsed successfully, CELIX_ILLEGAL_ARGUMENT if the version string + * was invalid, or CELIX_ENOMEM if memory could not be allocated. + */ +CELIX_UTILS_EXPORT celix_status_t celix_version_tryParse(const char* versionStr, celix_version_t** version); + /** * @brief Create empty version "0.0.0". */ diff --git a/libs/utils/src/filter.c b/libs/utils/src/filter.c index 0ad1fd4aa..c732bb40c 100644 --- a/libs/utils/src/filter.c +++ b/libs/utils/src/filter.c @@ -539,7 +539,7 @@ static celix_status_t celix_filter_compile(celix_filter_t* filter) { internal->boolValue = celix_utils_convertStringToBool(filter->value, false, &internal->convertedToBool); - celix_status_t convertStatus = celix_utils_convertStringToVersion(filter->value, NULL, &internal->versionValue); + celix_status_t convertStatus = celix_version_tryParse(filter->value, &internal->versionValue); if (convertStatus == ENOMEM) { return ENOMEM; } diff --git a/libs/utils/src/properties.c b/libs/utils/src/properties.c index 5c8b657e0..3ec19a2f7 100644 --- a/libs/utils/src/properties.c +++ b/libs/utils/src/properties.c @@ -74,27 +74,6 @@ struct celix_properties { int currentEntriesBufferIndex; }; -#define MALLOC_BLOCK_SIZE 5 - -static celix_status_t celix_properties_parseLine(const char* line, celix_properties_t* props); - -static void -celix_properties_updateBuffers(char** key, char** value, char** output, int outputPos, int* key_len, int* value_len) { - if (*output == *key) { - if (outputPos == (*key_len) - 1) { - (*key_len) += MALLOC_BLOCK_SIZE; - *key = realloc(*key, *key_len); - *output = *key; - } - } else { - if (outputPos == (*value_len) - 1) { - (*value_len) += MALLOC_BLOCK_SIZE; - *value = realloc(*value, *value_len); - *output = *value; - } - } -} - /** * Create a new string from the provided str by either using strdup or storing the string the short properties * optimization string buffer. @@ -347,249 +326,6 @@ void celix_properties_destroy(celix_properties_t* props) { } } -celix_properties_t* celix_properties_load(const char* filename) { - FILE* file = fopen(filename, "r"); - if (file == NULL) { - celix_err_pushf("Cannot open file '%s'", filename); - return NULL; - } - celix_properties_t* props = celix_properties_loadWithStream(file); - fclose(file); - return props; -} - -static celix_status_t celix_properties_parseLine(const char* line, celix_properties_t* props) { - int linePos; - int outputPos; - - bool precedingCharIsBackslash = false; - char* output = NULL; - int key_len = MALLOC_BLOCK_SIZE; - int value_len = MALLOC_BLOCK_SIZE; - linePos = 0; - precedingCharIsBackslash = false; - output = NULL; - outputPos = 0; - - // Ignore empty lines - if (line[0] == '\n' && line[1] == '\0') { - return CELIX_SUCCESS; - } - - celix_autofree char* key = calloc(1, key_len); - celix_autofree char* value = calloc(1, value_len); - if (!key || !value) { - celix_err_pushf("Cannot allocate memory for key or value. Got error %i", errno); - return CELIX_ENOMEM; - } - - key[0] = '\0'; - value[0] = '\0'; - - while (line[linePos] != '\0') { - if (line[linePos] == ' ' || line[linePos] == '\t') { - if (output == NULL) { - // ignore - linePos += 1; - continue; - } - } else { - if (output == NULL) { - output = key; - } - } - if (line[linePos] == '=' || line[linePos] == ':' || line[linePos] == '#' || line[linePos] == '!') { - if (precedingCharIsBackslash) { - // escaped special character - output[outputPos++] = line[linePos]; - celix_properties_updateBuffers(&key, &value, &output, outputPos, &key_len, &value_len); - precedingCharIsBackslash = false; - } else { - if (line[linePos] == '#' || line[linePos] == '!') { - if (outputPos == 0) { - // comment line, ignore - return CELIX_SUCCESS; - } else { - output[outputPos++] = line[linePos]; - celix_properties_updateBuffers(&key, &value, &output, outputPos, &key_len, &value_len); - } - } else { // = or : - if (output == value) { // already have a seperator - output[outputPos++] = line[linePos]; - celix_properties_updateBuffers(&key, &value, &output, outputPos, &key_len, &value_len); - } else { - output[outputPos++] = '\0'; - celix_properties_updateBuffers(&key, &value, &output, outputPos, &key_len, &value_len); - output = value; - outputPos = 0; - } - } - } - } else if (line[linePos] == '\\') { - if (precedingCharIsBackslash) { // double backslash -> backslash - output[outputPos++] = '\\'; - celix_properties_updateBuffers(&key, &value, &output, outputPos, &key_len, &value_len); - } - precedingCharIsBackslash = true; - } else { // normal character - precedingCharIsBackslash = false; - output[outputPos++] = line[linePos]; - celix_properties_updateBuffers(&key, &value, &output, outputPos, &key_len, &value_len); - } - linePos += 1; - } - if (output != NULL) { - output[outputPos] = '\0'; - } - - return celix_properties_set(props, celix_utils_trimInPlace(key), celix_utils_trimInPlace(value)); -} - -celix_properties_t* celix_properties_loadWithStream(FILE* file) { - if (file == NULL) { - return NULL; - } - - - celix_autoptr(celix_properties_t) props = celix_properties_create(); - if (!props) { - return NULL; - } - - int rc = fseek(file, 0, SEEK_END); - if (rc != 0) { - celix_err_pushf("Cannot seek to end of file. Got error %i", errno); - return NULL; - } - - long fileSize = ftell(file); - if (fileSize < 0) { - celix_err_pushf("Cannot get file size. Got error %i", errno); - return NULL; - } - - rc = fseek(file, 0, SEEK_SET); - if (rc != 0) { - celix_err_pushf("Cannot seek to start of file. Got error %i", errno); - return NULL; - } - - celix_autofree char* fileBuffer = malloc(fileSize + 1); - if (fileBuffer == NULL) { - celix_err_pushf("Cannot allocate memory for file buffer. Got error %i", errno); - return NULL; - } - - size_t rs = fread(fileBuffer, sizeof(char), fileSize, file); - if (rs < fileSize) { - celix_err_pushf("fread read only %zu bytes out of %zu\n", rs, fileSize); - return NULL; - } - fileBuffer[fileSize] = '\0'; // ensure a '\0' at the end of the fileBuffer - - char* savePtr = NULL; - char* line = strtok_r(fileBuffer, "\n", &savePtr); - while (line != NULL) { - celix_status_t status = celix_properties_parseLine(line, props); - if (status != CELIX_SUCCESS) { - celix_err_pushf("Failed to parse line '%s'", line); - return NULL; - } - line = strtok_r(NULL, "\n", &savePtr); - } - - return celix_steal_ptr(props); -} - -celix_properties_t* celix_properties_loadFromString(const char* input) { - celix_autoptr(celix_properties_t) props = celix_properties_create(); - celix_autofree char* in = celix_utils_strdup(input); - if (!props || !in) { - celix_err_push("Failed to create properties or duplicate input string"); - return NULL; - } - - char* line = NULL; - char* saveLinePointer = NULL; - line = strtok_r(in, "\n", &saveLinePointer); - while (line != NULL) { - celix_status_t status = celix_properties_parseLine(line, props); - if (status != CELIX_SUCCESS) { - celix_err_pushf("Failed to parse line '%s'", line); - return NULL; - } - line = strtok_r(NULL, "\n", &saveLinePointer); - } - return celix_steal_ptr(props); -} - -/** - * @brief Store properties string to file and escape the characters '#', '!', '=' and ':' if encountered. - */ -static int celix_properties_storeEscapedString(FILE* file, const char* str) { - int rc = 0; - size_t len = strlen(str); - for (size_t i = 0; i < len && rc != EOF; i += 1) { - if (str[i] == '#' || str[i] == '!' || str[i] == '=' || str[i] == ':') { - rc = fputc('\\', file); - if (rc == EOF) { - continue; - } - } - rc = fputc(str[i], file); - } - return rc; -} - -celix_status_t celix_properties_store(celix_properties_t* properties, const char* filename, const char* header) { - FILE* file = fopen(filename, "w+"); - - if (file == NULL) { - celix_err_pushf("Cannot open file '%s'", filename); - return CELIX_FILE_IO_EXCEPTION; - } - - int rc = 0; - - if (header && strstr("\n", header)) { - celix_err_push("Header cannot contain newlines. Ignoring header."); - } else if (header) { - rc = fputc('#', file); - if (rc != EOF) { - rc = fputs(header, file); - } - if (rc != EOF) { - rc = fputc('\n', file); - } - } - - CELIX_PROPERTIES_ITERATE(properties, iter) { - const char* val = iter.entry.value; - if (rc != EOF) { - rc = celix_properties_storeEscapedString(file, iter.key); - } - if (rc != EOF) { - rc = fputc('=', file); - } - if (rc != EOF) { - rc = celix_properties_storeEscapedString(file, val); - } - if (rc != EOF) { - rc = fputc('\n', file); - } - } - if (rc != EOF) { - rc = fclose(file); - } else { - fclose(file); - } - if (rc == EOF) { - celix_err_push("Failed to write properties to file"); - return CELIX_FILE_IO_EXCEPTION; - } - return CELIX_SUCCESS; -} - celix_properties_t* celix_properties_copy(const celix_properties_t* properties) { celix_properties_t* copy = celix_properties_create(); @@ -759,7 +495,7 @@ const char* celix_properties_getAsString(const celix_properties_t* properties, celix_status_t celix_properties_setString(celix_properties_t* properties, const char* key, const char* value) { - if (!properties) { + if (!properties) { return CELIX_SUCCESS; // silently ignore NULL properties } char* copy = celix_properties_createString(properties, value); diff --git a/libs/utils/src/properties_encoding.c b/libs/utils/src/properties_encoding.c index 53af5ec4b..93897b7a2 100644 --- a/libs/utils/src/properties_encoding.c +++ b/libs/utils/src/properties_encoding.c @@ -593,7 +593,7 @@ celix_status_t celix_properties_loadFromStream(FILE* stream, int decodeFlags, ce return celix_properties_decodeFromJson(root, decodeFlags, out); } -celix_status_t celix_properties_load2(const char* filename, int decodeFlags, celix_properties_t** out) { +celix_status_t celix_properties_load(const char* filename, int decodeFlags, celix_properties_t** out) { FILE* stream = fopen(filename, "r"); if (!stream) { celix_err_pushf("Failed to open file %s.", filename); @@ -604,7 +604,7 @@ celix_status_t celix_properties_load2(const char* filename, int decodeFlags, cel return status; } -celix_status_t celix_properties_loadFromString2(const char* input, int decodeFlags, celix_properties_t** out) { +celix_status_t celix_properties_loadFromString(const char* input, int decodeFlags, celix_properties_t** out) { FILE* stream = fmemopen((void*)input, strlen(input), "r"); if (!stream) { celix_err_push("Failed to open memstream."); diff --git a/libs/utils/src/version.c b/libs/utils/src/version.c index 15fd89b32..0ef56d528 100644 --- a/libs/utils/src/version.c +++ b/libs/utils/src/version.c @@ -112,7 +112,8 @@ celix_version_t* celix_version_createVersionFromString(const char *versionStr) { return version; } -celix_status_t celix_version_parse(const char* versionStr, celix_version_t** version) { +static celix_status_t +celix_version_parseInternal(const char* versionStr, bool logParseError, celix_version_t** version) { *version = NULL; if (versionStr == NULL) { @@ -128,16 +129,20 @@ celix_status_t celix_version_parse(const char* versionStr, celix_version_t** ver errno = 0; long l = strtol(token, &endPtr, 10); if (errno != 0 || token == endPtr || l < 0 || l >= INT_MAX) { - celix_err_pushf("Invalid version component(%d)", count); - return CELIX_ILLEGAL_ARGUMENT; + if (logParseError) { + celix_err_pushf("Invalid version part %d. Input str: %s", count, versionStr); + } + return CELIX_ILLEGAL_ARGUMENT; } versionsParts[count++] = (int)l; if (*endPtr == '.') { token = endPtr + 1; - } else if (celix_utils_isEndptrEndOfStringOrOnlyContainsWhitespaces(endPtr)){ + } else if (celix_utils_isEndptrEndOfStringOrOnlyContainsWhitespaces(endPtr)) { token = NULL; } else { - celix_err_pushf("Invalid trailing string:<%s>", endPtr); + if (logParseError) { + celix_err_pushf("Invalid trailing string `%s`. Input str: %s", endPtr, versionStr); + } return CELIX_ILLEGAL_ARGUMENT; } } @@ -148,6 +153,14 @@ celix_status_t celix_version_parse(const char* versionStr, celix_version_t** ver return *version ? CELIX_SUCCESS : (errno == EINVAL ? CELIX_ILLEGAL_ARGUMENT : CELIX_ENOMEM); } +celix_status_t celix_version_parse(const char* versionStr, celix_version_t** version) { + return celix_version_parseInternal(versionStr, true, version); +} + +celix_status_t celix_version_tryParse(const char* versionStr, celix_version_t** version) { + return celix_version_parseInternal(versionStr, false, version); +} + celix_version_t* celix_version_createEmptyVersion() { return celix_version_create(0, 0, 0, NULL); } diff --git a/misc/experimental/bundles/config_admin/config_admin_tst/config.properties.in b/misc/experimental/bundles/config_admin/config_admin_tst/config.properties.in index d4db56716..0d3133d7e 100644 --- a/misc/experimental/bundles/config_admin/config_admin_tst/config.properties.in +++ b/misc/experimental/bundles/config_admin/config_admin_tst/config.properties.in @@ -1,20 +1,5 @@ -# 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. - -CELIX_FRAMEWORK_FRAMEWORK_CACHE_DIR=@config_admin_bundle_file@ @example_test_bundle_file@ @example_test2_bundle_file@ -LOGHELPER_ENABLE_STDOUT_FALLBACK=true -CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE=true \ No newline at end of file +{ + "CELIX_FRAMEWORK_FRAMEWORK_CACHE_DIR":"@config_admin_bundle_file@ @example_test_bundle_file@ @example_test2_bundle_file@", + "LOGHELPER_ENABLE_STDOUT_FALLBACK":true, + "CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE":true +} \ No newline at end of file