You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
112.3.11 Circular References
It is possible for a set of component descriptions to create a circular dependency. For example, if component A references a service provided by component B and component B references a service provided by component A then a component configuration of one component cannot be satisfied without accessing a partially activated component instance of the other component. SCR must ensure that a component instance is never accessible to another component instance or as a service until it has been fully activated, that is it has returned from its activate method if it has one.
Circular references must be detected by SCR when it attempts to satisfy component configurations and SCR must fail to satisfy the references involved in the cycle and log an error message with the Log Service, if present. However, if one of the references in the cycle has optional cardinality SCR must break the cycle. The reference with the optional cardinality can be satisfied and bound to zero target services. Therefore the cycle is broken and the other references may be satisfied.
Consider the following test case:
#include <chrono>
#include <gtest/gtest.h>
#include "../src/manager/ComponentConfigurationImpl.hpp"
#include "../src/manager/ReferenceManager.hpp"
#include "../src/manager/SingletonComponentConfiguration.hpp"
#include "cppmicroservices/Framework.h"
#include "cppmicroservices/FrameworkFactory.h"
#include "cppmicroservices/FrameworkEvent.h"
#include "Mocks.hpp"
#include "TestUtils.hpp"
namespace scr = cppmicroservices::service::component::runtime;
namespace cppmicroservices {
namespace scrimpl {
TEST(TestCircuarReference, circularReferenceTest) {
auto mockMetadata = std::make_shared<metadata::ComponentMetadata>();
auto mockRegistry = std::make_shared<MockComponentRegistry>();
auto fakeLogger = std::make_shared<FakeLogger>();
// service component A requires a reference to a service from service component B and B
// requires a reference to a service from service component A.
// In this case, neither A nor B will be satisfied and an error should be
// logged about detecting a circular dependency.
// NOTE: Optional cardinality on either of these references will break the cycle and allow
// the service components to be satisfied.
auto componentAMetadata = std::make_shared<metadata::ComponentMetadata>();
auto componentBMetadata = std::make_shared<metadata::ComponentMetadata>();
componentAMetadata->implClassName = us_service_interface_iid<dummy::Reference1>();
componentBMetadata->implClassName = us_service_interface_iid<dummy::Reference2>();
metadata::ReferenceMetadata referenceA;
referenceA.interfaceName = us_service_interface_iid<dummy::Reference1>();
referenceA.name = std::move(std::string{"ref"});
metadata::ReferenceMetadata referenceB;
referenceB.interfaceName = us_service_interface_iid<dummy::Reference2>();
referenceB.name = std::move(std::string{"ref"});
componentAMetadata->refsMetadata.emplace_back(referenceA);
componentBMetadata->refsMetadata.emplace_back(referenceB);
auto framework = cppmicroservices::FrameworkFactory().NewFramework();
framework.Start();
auto context = framework.GetBundleContext();
auto asyncWorkSvc = std::make_shared<SCRAsyncWorkService>(context, fakeLogger);
auto configNotifier = std::make_shared<ConfigurationNotifier>(context, fakeLogger, asyncWorkSvc);
auto managers =
std::make_shared<std::vector<std::shared_ptr<ComponentManager>>>();
auto componentA = std::make_shared<SingletonComponentConfigurationImpl>(componentAMetadata, framework, mockRegistry, fakeLogger, configNotifier, managers);
auto componentB = std::make_shared<SingletonComponentConfigurationImpl>(componentBMetadata, framework, mockRegistry, fakeLogger, configNotifier, managers);
componentA->Initialize();
componentA->Register();
componentB->Initialize();
componentB->Register();
ASSERT_EQ(cppmicroservices::service::component::runtime::dto::ComponentState::UNSATISFIED_REFERENCE,
componentA->GetState()->GetValue());
ASSERT_EQ(cppmicroservices::service::component::runtime::dto::ComponentState::UNSATISFIED_REFERENCE,
componentB->GetState()->GetValue());
framework.Stop();
framework.WaitForStop(std::chrono::milliseconds::zero());
}
// TODO: TEST: SCR must ensure that a component instance or a service is never accessible until it has been
// "fully activated", meaning the service component's Activate method has returned, if present.
}
}
neither componentA nor componentB should be satisfied.
Additionally a manual code inspection indicates that DS exposes the service before the service component has finished activation.
The text was updated successfully, but these errors were encountered:
Given the following from the DS OSGi spec:
Consider the following test case:
neither componentA nor componentB should be satisfied.
Additionally a manual code inspection indicates that DS exposes the service before the service component has finished activation.
The text was updated successfully, but these errors were encountered: