Skip to content

Commit

Permalink
Factory Configuration Bug Fix (#731)
Browse files Browse the repository at this point in the history
* Factory Configuration Bug Fix

When factory configurations are created before the bundle containing the factory component is installed and started, DS should find those configurations in the Configuration Admin repository and register them as part of the factory component startup. Signed-off-by The MathWorks, Inc. <pelliott@mathworks.com>

* Factory Configuration Bug fix

Addressed code review feedback. Signed-off-by The MathWorks, Inc. <pelliott@mathworks.com>

* Update ComponentConfigurationImpl.cpp

Fixed compilation failure in Ubuntu Minimum Gcc build. Signed-off-by The MathWorks, Inc. <pelliott@mathworks.com>

* Update TestFactoryPid.cpp

Change auto const to constexpr. Signed-off-by The MathWorks, Inc. <pelliott@mathworks.com>
  • Loading branch information
pelliott-mathworks committed Oct 6, 2022
1 parent 23cf347 commit 22c8387
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,31 @@ void ComponentConfigurationImpl::Initialize()
if (AreReferencesSatisfied() && configManager->IsConfigSatisfied()) {
GetState()->Register(*this);
}
// For factory components, see if any configuration objects for factory instances
// were created before the factory component was started. If so, create the factory
// component instances.
if (!metadata->factoryComponentID.empty()) {
auto sr = this->bundle.GetBundleContext().GetServiceReference<
cppmicroservices::service::cm::ConfigurationAdmin>();
if (!sr) {
throw std::runtime_error("ComponentConfigurationImpl - Could not get "
"ConfigurationAdmin service reference");
}
auto configAdmin =
this->bundle.GetBundleContext()
.GetService<cppmicroservices::service::cm::ConfigurationAdmin>(sr);
if (!configAdmin) {
throw std::runtime_error("ComponentConfigurationImpl - Could not get "
"ConfigurationAdmin service");
}
auto configs = configAdmin->ListConfigurations("(pid=" + metadata->configurationPids[0] + "~*)");
std::shared_ptr<ComponentConfigurationImpl> mgr = shared_from_this();
if (!configs.empty()) {
for (const auto& config : configs) {
configNotifier->CreateFactoryComponent(config->GetPid(), mgr);
}
}
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,10 @@ bool ConfigurationNotifier::AnyListenersForPid(const std::string& pid) noexcept
return false;
}
} //release listenersMapHandle lock
CreateFactoryComponent(factoryName, pid, mgr);
CreateFactoryComponent(pid, mgr);
return true;
}
void ConfigurationNotifier::CreateFactoryComponent(
const std::string& factoryName,
const std::string& pid,
std::shared_ptr<ComponentConfigurationImpl>& mgr)
{
Expand All @@ -155,7 +154,7 @@ void ConfigurationNotifier::CreateFactoryComponent(
// component except the factory component itself.
newMetadata->configurationPids.clear();
for (const auto& basePid : oldMetadata->configurationPids) {
if (basePid != factoryName) {
if (basePid != oldMetadata->configurationPids[0]) {
newMetadata->configurationPids.emplace_back(basePid);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,9 @@ class ConfigurationNotifier final
cppmicroservices::service::cm::ConfigurationEventType type,
std::shared_ptr<cppmicroservices::AnyMap> properties);

private:
void CreateFactoryComponent(const std::string& factoryName,
const std::string& pid,
void CreateFactoryComponent(const std::string& pid,
std::shared_ptr<ComponentConfigurationImpl>& mgr);
private:

using TokenMap = std::unordered_map<ListenerTokenId, Listener>;

Expand Down
43 changes: 43 additions & 0 deletions compendium/DeclarativeServices/test/TestFactoryPid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,49 @@ TEST_F(tServiceComponent, testFactoryPidConstructionNameDifferentThanClass)
auto instance = GetInstance<test::CAInterface>();
ASSERT_TRUE(instance) << "GetService failed for CAInterface";


}

/* testFactoryConfigBeforeInstall
This test creates the configuration objects for the factory instances
before the factory component has been installed and started.
Once the factory component is installed and started the instances
associated with the configuration objects should be registered
automatically by DS.
*/
TEST_F(tServiceComponent, testFactoryConfigBeforeInstall)
{
std::string configurationPid = "ServiceComponentPid";

// Get a service reference to ConfigAdmin to create the factory component instances.
auto configAdminService =
GetInstance<cppmicroservices::service::cm::ConfigurationAdmin>();
ASSERT_TRUE(configAdminService) << "GetService failed for ConfigurationAdmin";

// Create some factory configuration objects.
constexpr auto count = 5;
for (int i = 0; i < count; i++) {
// Create the factory configuration object
auto factoryConfig =
configAdminService->CreateFactoryConfiguration(configurationPid);

// Update the properties for the factory configuration object
cppmicroservices::AnyMap props(
cppmicroservices::AnyMap::UNORDERED_MAP_CASEINSENSITIVE_KEYS);
const std::string instanceId{ "instance" + std::to_string(i)};
props["uniqueProp"] = instanceId;
auto fut = factoryConfig->Update(props);
fut.get();
}

// Start the test bundle containing the factory component. This will
// cause DS to register the factory instances.
cppmicroservices::Bundle testBundle = StartTestBundle("TestBundleDSCA21");

//Request service references to the new component instances. This will
//cause DS to construct the factory instances.
auto instances = GetInstances<test::CAInterface>();
EXPECT_EQ(instances.size(), count);
}
}

15 changes: 15 additions & 0 deletions compendium/DeclarativeServices/test/TestFixture.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,21 @@ class tServiceComponent : public testing::Test
return context.GetService<T>(instanceRef);
}

template<class T>
std::vector<std::shared_ptr<T>> GetInstances()
{
std::vector<cppmicroservices::ServiceReference<T>> instanceRefs;
std::vector<std::shared_ptr<T>> instances;
instanceRefs = context.GetServiceReferences<T>();
if (instanceRefs.empty()) {
return std::vector<std::shared_ptr<T>>();
}
for (const auto& ref : instanceRefs) {
instances.push_back(context.GetService<T>(ref));
}
return instances;
}

std::vector<scr::dto::ComponentConfigurationDTO> GetComponentConfigs(
const cppmicroservices::Bundle& testBundle,
const std::string& componentName,
Expand Down

0 comments on commit 22c8387

Please sign in to comment.