Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/585 celix conditions #588

Merged
merged 38 commits into from
Jul 31, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
1af0812
Add initial setup for OSGi-like conditions
pnoltes Jun 27, 2023
cb9f45d
Fix query command to include framework services
pnoltes Jun 27, 2023
69fb405
Disable condition in framwork
pnoltes Jun 28, 2023
db65a81
Merge branch 'feature/scheduled_event_on_event_thread' into feature/o…
pnoltes Jun 28, 2023
b5964b6
Refactor conditions to framework bundle
pnoltes Jun 29, 2023
116f92f
Add FrameworkConditionsTestSuite and refactor fw conditions impl
pnoltes Jun 30, 2023
908f932
Add error injection tests for fw bundle and factory
pnoltes Jul 1, 2023
1ace083
Add framework celix_condition services documentation
pnoltes Jul 1, 2023
d9e4290
Merge branch 'feature/scheduled_event_on_event_thread' into feature/5…
pnoltes Jul 4, 2023
f07f6e2
Add component.ready framework condition
pnoltes Jul 6, 2023
97c3e49
Merge branch 'feature/scheduled_event_on_event_thread' into feature/5…
pnoltes Jul 10, 2023
ba48303
Cleanup framework_start
pnoltes Jul 10, 2023
926a94c
Merge branch 'master' into feature/585-celix-conditions
pnoltes Jul 11, 2023
c329f64
Remove unused source files
pnoltes Jul 11, 2023
5cc100d
Fix some minor documentation / comments
pnoltes Jul 11, 2023
cc323ef
Remove dead code.
PengZheng Jul 12, 2023
9998dd9
Move the components.ready check from fw bundle to a separate bundle
pnoltes Jul 24, 2023
2300199
Add install of components_ready_api headers
pnoltes Jul 25, 2023
390903a
Add components ready check to conanfile
pnoltes Jul 25, 2023
e20b562
Update documentation for components ready check
pnoltes Jul 25, 2023
aebbf58
Fix invalid integer division to floating-point division in C++ use se…
pnoltes Jul 25, 2023
228d567
Refactor nextDeadline fw function
pnoltes Jul 25, 2023
aa4d438
Update timing in components ready test suite
pnoltes Jul 25, 2023
5a44d82
Add missing build option to conanfile.py
pnoltes Jul 25, 2023
aab28be
Refactor WaitForScheduledEventTest into 2 tests
pnoltes Jul 27, 2023
46e98e9
Remove unused (when build type is not debug) variable.
pnoltes Jul 27, 2023
db93e5a
Disable fw services for some ei test suites
pnoltes Jul 30, 2023
c509283
Add macos and linux prefix to ci build names
pnoltes Jul 30, 2023
aa3e7d5
Refactor ScheduledEventTestSuite to work with a "build on ci" option
pnoltes Jul 30, 2023
f34f845
Configure "build on ci" for github ci actions
pnoltes Jul 30, 2023
6fc1098
Rename "build on ci" cmake var to ENABLE_TESTING_ON_CI
pnoltes Jul 30, 2023
360f2b4
Add "build on ci" configuration to test_framework_with_cxx14
pnoltes Jul 30, 2023
9c961f5
Add "build on ci" configuration to components ready test suite
pnoltes Jul 30, 2023
0843c18
Add additional ei test for framework bundle
pnoltes Jul 30, 2023
d223f7e
Fix memleak in framework bundle
pnoltes Jul 30, 2023
5f77f42
Relax timing requirements for CI testing on macos
pnoltes Jul 30, 2023
efc629d
Merge branch 'master' into feature/585-celix-conditions
PengZheng Jul 31, 2023
43a9131
Add missing intra-package dependency deduction and test package.
PengZheng Jul 31, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions bundles/shell/shell/gtest/src/ShellTestSuite.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "celix_bundle_context.h"
#include "celix_shell.h"
#include "celix_framework_utils.h"
#include "celix_constants.h"

class ShellTestSuite : public ::testing::Test {
public:
Expand All @@ -40,6 +41,9 @@ class ShellTestSuite : public ::testing::Test {
celix_properties_set(properties, "org.osgi.framework.storage", ".cacheShellTestSuite");
celix_properties_set(properties, "CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL", "trace");

//to ensure "query 0" is still a test case for am empty result.
celix_properties_setBool(properties, CELIX_FRAMEWORK_CONDITION_SERVICES_ENABLED, false);

auto* cFw = celix_frameworkFactory_createFramework(properties);
auto cCtx = celix_framework_getFrameworkContext(cFw);

Expand Down
16 changes: 10 additions & 6 deletions bundles/shell/shell/src/query_command.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@
#include <string.h>
#include <stdlib.h>

#include "celix_bundle.h"
#include "celix_bundle_context.h"
#include "celix_constants.h"
#include "celix_framework.h"
#include "celix_shell_constants.h"
#include "celix_bundle_context.h"
#include "std_commands.h"
#include "celix_bundle.h"
#include "celix_utils.h"

#include "std_commands.h"

struct query_options {
bool useColors;
Expand Down Expand Up @@ -143,9 +143,13 @@ static void queryCommand_listServices(celix_bundle_context_t *ctx, const struct
data.nrOfProvidedServicesFound = 0;
data.nrOfRequestedServicesFound = 0;

if (opts->bndId >= 0L) {
if (opts->bndId >= CELIX_FRAMEWORK_BUNDLE_ID) {
queryCommand_listServicesForBundle(ctx, opts->bndId, &data, opts, sout, serr);
} else {
//query framework bundle
queryCommand_listServicesForBundle(ctx, CELIX_FRAMEWORK_BUNDLE_ID, &data, opts, sout, serr);

//query rest of the bundles
celix_array_list_t *bundleIds = celix_bundleContext_listBundles(ctx);
for (int i = 0; i < celix_arrayList_size(bundleIds); ++i) {
long bndId = celix_arrayList_getLong(bundleIds, i);
Expand Down Expand Up @@ -199,7 +203,7 @@ bool queryCommand_execute(void *_ptr, const char *command_line_str, FILE *sout,
//check if its a number (bundle id)
errno = 0;
long bndId = strtol(sub_str, NULL, 10);
if (bndId > 0 && errno == 0 /*not EINVAL*/) {
if (bndId >= CELIX_FRAMEWORK_BUNDLE_ID && errno == 0 /*not EINVAL*/) {
opts.bndId = bndId;
} else {
//not option and not a bundle id -> query
Expand Down
30 changes: 30 additions & 0 deletions documents/framework.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,36 @@ add_executable(create_framework_with_celix_launcher src/launcher.c)
target_link_libraries(create_framework_with_celix_launcher PRIVATE Celix::framework)
```

## Framework `celix_condition` Services
In a dynamic framework such as Apache Celix, it can sometimes be challenging to ascertain when the framework or
certain parts of a dynamic service-based application are ready for use. To address this issue, Apache Celix provides
services known as `celix_condition` services.

A `celix_condition` service is a registered marker interface with a "condition.id" service property.
The service's availability signifies that the condition identified by the "condition.id" has been met.

The `celix_condition` service is an adaptation of the
[OSGi 8 Condition Service Specification](https://docs.osgi.org/specification/osgi.core/8.0.0/service.condition.html).

The Apache Celix framework will provide the following `celix_condition` services for the respective states:

- Celix condition "true", which is always available.
- Celix condition "framework.ready". This service will be registered when the framework has successfully and fully
started, which includes installing and starting all configured bundles and services, and ensuring the event queue is
empty after all configured bundles have been started. Note that the "framework.ready" condition is not part of the
PengZheng marked this conversation as resolved.
Show resolved Hide resolved
OSGi condition specification.
- Celix condition "framework.error". This service will be registered when the framework has not started successfully.
This can occur if any of the configured bundles fail to start or install. Note that the "framework.error" condition
is not part of the OSGi condition specification.
- Celix condition "components.ready". This service will be registered when the "framework.ready" or "framework.error"
service is registered, all components have become active and the event queue is empty.
PengZheng marked this conversation as resolved.
Show resolved Hide resolved
Note that the "components.ready" condition is not part of the OSGi condition specification.

Contrary to the OSGi specification, the Apache Celix framework does not provide a public API for adding or removing
framework listeners. Instead, framework condition services can be used. This has the advantage of ensuring no
framework state changes can be missed, because the state indicating condition services will be available
until the framework is stopped.

## Framework bundle cache
The Apache Celix framework uses a bundle cache directory to store the installed bundles, their state and for a
persistent bundle storage. The bundle cache directory is created in the directory configured in the framework
Expand Down
1 change: 1 addition & 0 deletions libs/framework/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ set(FRAMEWORK_SRC
src/celix_bundle_state.c
src/celix_framework_utils.c
src/celix_scheduled_event.c
src/celix_framework_bundle.c
)
set(FRAMEWORK_DEPS libuuid::libuuid CURL::libcurl ZLIB::ZLIB ${CMAKE_DL_LIBS})

Expand Down
12 changes: 10 additions & 2 deletions libs/framework/gtest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ celix_bundle_headers(bundle_with_bad_export "Export-Library: $<SEMICOLON>")
add_celix_bundle(simple_cxx_bundle SOURCES src/HelloWorldCxxActivator.cc VERSION 1.0.0)
celix_bundle_libs(simple_cxx_bundle "PRIVATE" TRUE Celix::framework)
add_celix_bundle(simple_cxx_dep_man_bundle SOURCES src/HelloWorldCxxActivatorWithDepMan.cc VERSION 1.0.0)
add_celix_bundle(cmp_test_bundle SOURCES src/CmpTestBundleActivator.cc)
add_celix_bundle(cmp_test_bundle SOURCES src/CmpTestBundleActivator.cc VERSION 1.0.0)
add_celix_bundle(cond_test_bundle SOURCES src/CondTestBundleActivator.cc VERSION 1.0.0)
add_subdirectory(subdir) #simple_test_bundle4, simple_test_bundle5 and sublib

add_celix_bundle(unresolvable_bundle SOURCES src/nop_activator.c VERSION 1.0.0)
Expand All @@ -52,12 +53,13 @@ set(CELIX_FRAMEWORK_TEST_SOURCES
src/DependencyManagerTestSuite.cc
src/CxxBundleContextTestSuite.cc
src/HelloWorldCxxActivator.cc
src/CxxFrameworkFactoryTestSuite.cc
src/FrameworkFactoryTestSuite.cc
src/CxxBundleActivatorTestSuite.cc
src/BundleArchiveTestSuite.cc
src/CelixLauncherTestSuite.cc
src/CelixBundleCacheTestSuite.cc
src/ScheduledEventTestSuite.cc
src/FrameworkBundleTestSuite.cc
)

add_executable(test_framework ${CELIX_FRAMEWORK_TEST_SOURCES})
Expand Down Expand Up @@ -99,6 +101,7 @@ celix_get_bundle_filename(unresolvable_bundle UNRESOLVABLE_BUNDLE)
celix_get_bundle_file(simple_cxx_bundle SIMPLE_CXX_BUNDLE_LOC)
celix_get_bundle_file(simple_cxx_dep_man_bundle SIMPLE_CXX_DEP_MAN_BUNDLE_LOC)
celix_get_bundle_file(cmp_test_bundle CMP_TEST_BUNDLE_LOC)
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)
Expand All @@ -118,6 +121,7 @@ target_compile_definitions(test_framework PRIVATE
CMP_TEST_BUNDLE_LOC="${CMP_TEST_BUNDLE_LOC}"
SIMPLE_CXX_DEP_MAN_BUNDLE_LOC="${SIMPLE_CXX_DEP_MAN_BUNDLE_LOC}"
CMP_TEST_BUNDLE_LOC="${CMP_TEST_BUNDLE_LOC}"
COND_TEST_BUNDLE_LOC="${COND_TEST_BUNDLE_LOC}"
INSTALL_AND_START_BUNDLES_CONFIG_PROPERTIES_FILE="${CMAKE_CURRENT_BINARY_DIR}/install_and_start_bundles.properties"
)
add_test(NAME test_framework COMMAND test_framework)
Expand All @@ -130,6 +134,8 @@ if (LINKER_WRAP_SUPPORTED)
src/CelixBundleContextBundlesWithErrorTestSuite.cc
src/CelixBundleCacheErrorInjectionTestSuite.cc
src/ScheduledEventWithErrorInjectionTestSuite.cc
src/FrameworkBundleWithErrorInjectionTestSuite.cc
src/FrameworkFactoryWithErrorInjectionTestSuite.cc
)
target_compile_definitions(test_framework_with_ei PRIVATE
SIMPLE_TEST_BUNDLE1_LOCATION="${SIMPLE_TEST_BUNDLE1}"
Expand All @@ -150,6 +156,7 @@ if (LINKER_WRAP_SUPPORTED)
Celix::properties_ei
Celix::stdlib_ei
Celix::stat_ei
Celix::threads_ei
GTest::gtest GTest::gtest_main
)

Expand Down Expand Up @@ -222,6 +229,7 @@ if (ENABLE_TESTING_FOR_CXX14)
CMP_TEST_BUNDLE_LOC="${CMP_TEST_BUNDLE_LOC}"
SIMPLE_CXX_DEP_MAN_BUNDLE_LOC="${SIMPLE_CXX_DEP_MAN_WITH_CXX11_BUNDLE_LOC}"
CMP_TEST_BUNDLE_LOC="${CMP_TEST_BUNDLE_LOC}"
COND_TEST_BUNDLE_LOC="${COND_TEST_BUNDLE_LOC}"
INSTALL_AND_START_BUNDLES_CONFIG_PROPERTIES_FILE="${CMAKE_CURRENT_BINARY_DIR}/install_and_start_bundles.properties"
)
add_test(NAME test_framework_with_cxx14 COMMAND test_framework_with_cxx14)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@
class BundleArchiveWithErrorInjectionTestSuite : public ::testing::Test {
public:
BundleArchiveWithErrorInjectionTestSuite() {
fw = celix::createFramework(
{{"CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL", "trace"}, {CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE, "true"}});
fw = celix::createFramework({{"CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL", "trace"},
{CELIX_FRAMEWORK_CLEAN_CACHE_DIR_ON_CREATE, "true"},
{CELIX_FRAMEWORK_CONDITION_SERVICES_ENABLED, "false"}});
ctx = fw->getFrameworkBundleContext();
}

Expand Down
10 changes: 6 additions & 4 deletions libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,12 @@ class CelixBundleContextBundlesTestSuite : public ::testing::Test {
const char * const TEST_BND_UNRESOLVABLE_LOC = "" TEST_BUNDLE_UNRESOLVABLE_LOCATION "";

CelixBundleContextBundlesTestSuite() {
properties = properties_create();
properties_set(properties, "LOGHELPER_ENABLE_STDOUT_FALLBACK", "true");
properties_set(properties, "org.osgi.framework.storage.clean", "true");
properties_set(properties, "org.osgi.framework.storage", ".cacheBundleContextTestFramework");
properties = celix_properties_create();
celix_properties_set(properties, "LOGHELPER_ENABLE_STDOUT_FALLBACK", "true");
celix_properties_set(properties, "org.osgi.framework.storage.clean", "true");
celix_properties_set(properties, "org.osgi.framework.storage", ".cacheBundleContextTestFramework");
celix_properties_set(properties, "CELIX_FRAMEWORK_CONDITION_SERVICES_ENABLED", "false");


fw = celix_frameworkFactory_createFramework(properties);
ctx = framework_getContext(fw);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class CelixBundleContextServicesTestSuite : public ::testing::Test {
celix_properties_set(properties, "org.osgi.framework.storage.clean", "onFirstInit");
celix_properties_set(properties, "org.osgi.framework.storage", ".cacheBundleContextTestFramework");
celix_properties_set(properties, "CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL", "trace");
celix_properties_set(properties, "CELIX_FRAMEWORK_CONDITION_SERVICES_ENABLED", "false");
celix_properties_setLong(properties, CELIX_FRAMEWORK_STATIC_EVENT_QUEUE_SIZE, 256); //ensure that the floodEventLoopTest overflows the static event queue size

fw = celix_frameworkFactory_createFramework(properties);
Expand Down
51 changes: 51 additions & 0 deletions libs/framework/gtest/src/CondTestBundleActivator.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* 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 "celix/BundleActivator.h"
#include "celix_condition.h"

/**
* @brief Empty Test Component for testing the condition service
*/
class CondComponent {
public:
CondComponent() = default;
};

class CondTestBundleActivator {
public:
explicit CondTestBundleActivator(const std::shared_ptr<celix::BundleContext>& ctx) {
registration = ctx->registerUnmanagedService<celix_condition>(&condition, CELIX_CONDITION_SERVICE_NAME)
.addProperty(CELIX_CONDITION_ID, "test")
.build();

auto& cmp = ctx->getDependencyManager()->createComponent<CondComponent>();
cmp.createServiceDependency<celix_condition>(CELIX_CONDITION_SERVICE_NAME)
.setFilter("(condition.id=does-not-exists)")
.setRequired(true);

cmp.build();
}

private:
std::shared_ptr<celix::ServiceRegistration> registration{};
celix_condition condition{};
};

CELIX_GEN_CXX_BUNDLE_ACTIVATOR(CondTestBundleActivator)
8 changes: 4 additions & 4 deletions libs/framework/gtest/src/CxxBundleContextTestSuite.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ class CxxBundleContextTestSuite : public ::testing::Test {
static constexpr const char * const TEST_BND2_LOC = "" SIMPLE_TEST_BUNDLE2_LOCATION "";

CxxBundleContextTestSuite() {
auto* properties = properties_create();
properties_set(properties, "LOGHELPER_ENABLE_STDOUT_FALLBACK", "true");
properties_set(properties, "org.osgi.framework.storage.clean", "onFirstInit");
properties_set(properties, "org.osgi.framework.storage", ".cacheCxxBundleContextTestFramework");
auto* properties = celix_properties_create();
celix_properties_set(properties, "LOGHELPER_ENABLE_STDOUT_FALLBACK", "true");
celix_properties_set(properties, "org.osgi.framework.storage.clean", "onFirstInit");
celix_properties_set(properties, "CELIX_FRAMEWORK_CONDITION_SERVICES_ENABLED", "false");

auto* cfw = celix_frameworkFactory_createFramework(properties);
fw = std::shared_ptr<celix_framework_t>{cfw, [](celix_framework_t* f){ celix_frameworkFactory_destroyFramework(f); }};
Expand Down
Loading