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