Alexandria 2.31.0
SDC-CH common library for the Euclid project
Loading...
Searching...
No Matches
ConfigManager.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2012-2022 Euclid Science Ground Segment
3 *
4 * This library is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License as published by the Free
6 * Software Foundation; either version 3.0 of the License, or (at your option)
7 * any later version.
8 *
9 * This library is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12 * details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this library; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
29
30namespace po = boost::program_options;
31
32namespace Euclid {
33namespace Configuration {
34
37
39 auto& manager_ptr = manager_map[id];
40 if (manager_ptr == nullptr) {
41 manager_ptr.reset(new ConfigManager{id});
42 }
43 return *manager_ptr;
44}
45
47 manager_map.erase(id);
48}
49
50ConfigManager::ConfigManager(long id) : m_id{id} {}
51
54 const std::type_index& root,
55 const std::pair<const std::type_index, std::set<std::type_index>>& config_pair) {
56
57 if (config_pair.second.find(root) != config_pair.second.end()) {
58 return {root};
59 }
60 for (auto& config : config_pair.second) {
61 auto found = hasCircularDependencies(dependency_map, root, *dependency_map.find(config));
62 if (!found.empty()) {
63 std::vector<std::type_index> result{config};
64 std::copy(found.begin(), found.end(), std::back_inserter(result));
65 return result;
66 }
67 }
68 return {};
69}
70
73 logger.debug() << "Cleaning dependencies of unregistered configurations...";
74 std::vector<std::type_index> unregistered_keys{};
75 for (auto& pair : dep_map) {
76 if (dict.find(pair.first) == dict.end()) {
77 unregistered_keys.emplace_back(pair.first);
78 continue;
79 }
80 std::vector<std::type_index> unregistered_values{};
81 for (auto& value : pair.second) {
82 if (dict.find(value) == dict.end()) {
83 unregistered_values.emplace_back(value);
84 }
85 }
86 for (auto& to_remove : unregistered_values) {
87 logger.debug() << "Removing configuration dependency " << pair.first.name() << " -> " << to_remove.name();
88 pair.second.erase(to_remove);
89 }
90 }
91 for (auto& to_remove : unregistered_keys) {
92 for (auto& value : dep_map.at(to_remove)) {
93 logger.debug() << "Removing configuration dependency " << to_remove.name() << " -> " << value.name();
94 }
95 dep_map.erase(to_remove);
96 }
97}
98
99po::options_description ConfigManager::closeRegistration() {
101
102 // Populate the dependencies map
103 for (auto& pair : m_config_dictionary) {
104 m_dependency_map[pair.first].insert(pair.second->getDependencies().begin(), pair.second->getDependencies().end());
105 }
106
107 // Cleanup any dependencies related with non register configurations
109
110 // Check for circular dependencies
111 for (auto& pair : m_config_dictionary) {
112 auto found = hasCircularDependencies(m_dependency_map, pair.first, *m_dependency_map.find(pair.first));
113 if (!found.empty()) {
114 logger.error() << "Found circular dependency between configurations:";
115 int count = 0;
116 logger.error() << " " << ++count << " : " << pair.first.name();
117 for (auto& type : found) {
118 logger.error() << " " << ++count << " : " << type.name();
119 }
120 throw Elements::Exception() << "Circular dependency between configurations";
121 }
122 }
123
125 for (auto& config : m_config_dictionary) {
126 for (auto& pair : config.second->getProgramOptions()) {
127 if (all_options.find(pair.first) == all_options.end()) {
128 // cppcheck-suppress stlFindInsert
129 all_options.emplace(pair.first, po::options_description{pair.first});
130 }
131 auto& group = all_options.at(pair.first);
132 for (auto& option : pair.second) {
133 group.add(boost::shared_ptr<po::option_description>{new po::option_description{option}});
134 }
135 }
136 }
137
138 po::options_description result{};
139 for (auto& pair : all_options) {
140 result.add(pair.second);
141 }
142
143 return result;
144}
145
147 const std::map<std::type_index, std::set<std::type_index>>& dependency_map,
149 const std::type_index& config) {
150 if (dictionary.at(config)->getCurrentState() >= Configuration::State::INITIALIZED) {
151 return;
152 }
153
154 for (auto& dependency : dependency_map.at(config)) {
155 recursiveInitialization(dictionary, dependency_map, user_values, dependency);
156 }
157
158 dictionary.at(config)->initialize(user_values);
159 dictionary.at(config)->getCurrentState() = Configuration::State::INITIALIZED;
160}
161
162void ConfigManager::initialize(const std::map<std::string, po::variable_value>& user_values) {
163 m_state = State::INITIALIZED;
164 for (auto& pair : m_config_dictionary) {
165 logger.debug() << "Pre-Initializing configuration :" << pair.first.name();
166 pair.second->preInitialize(user_values);
167 pair.second->getCurrentState() = Configuration::State::PRE_INITIALIZED;
168 }
169 for (auto& pair : m_config_dictionary) {
170 logger.debug() << "Initializing configuration :" << pair.first.name();
171 recursiveInitialization(m_config_dictionary, m_dependency_map, user_values, pair.first);
172 }
173 for (auto& pair : m_config_dictionary) {
174 logger.debug() << "Post-Initializing configuration :" << pair.first.name();
175 pair.second->postInitialize(user_values);
176 pair.second->getCurrentState() = Configuration::State::FINAL;
177 }
178}
179
180} // namespace Configuration
181} // namespace Euclid
static Elements::Logging logger
Logger.
Definition Example.cpp:55
T back_inserter(T... args)
void error(const std::string &logMessage)
void debug(const std::string &logMessage)
static Logging getLogger(const std::string &name="")
Manages a set of configuration classes.
std::map< std::type_index, std::unique_ptr< Configuration > > m_config_dictionary
std::map< std::type_index, std::set< std::type_index > > m_dependency_map
boost::program_options::options_description closeRegistration()
Terminates the manager registration phase.
static ConfigManager & getInstance(long id)
Returns a reference to the ConfigManager with the given ID.
T copy(T... args)
T emplace_back(T... args)
T emplace(T... args)
T find(T... args)
T insert(T... args)
std::vector< std::type_index > hasCircularDependencies(const std::map< std::type_index, std::set< std::type_index > > &dependency_map, const std::type_index &root, const std::pair< const std::type_index, std::set< std::type_index > > &config_pair)
static Elements::Logging logger
static std::map< long, std::unique_ptr< ConfigManager > > manager_map
static void recursiveInitialization(const std::map< std::type_index, std::unique_ptr< Configuration > > &dictionary, const std::map< std::type_index, std::set< std::type_index > > &dependency_map, const std::map< std::string, po::variable_value > &user_values, const std::type_index &config)
static void cleanupNonRegisteredDependencies(std::map< std::type_index, std::set< std::type_index > > &dep_map, const std::map< std::type_index, std::unique_ptr< Configuration > > &dict)