Belle II Software  release-08-01-10
ModuleManager.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 #include <framework/core/Module.h>
10 #include <framework/core/ModuleManager.h>
11 #include <framework/utilities/FileSystem.h>
12 #include <framework/logging/Logger.h>
13 
14 #include <regex>
15 #include <fstream>
16 
17 using namespace Belle2;
18 using namespace std;
19 
20 #define MAP_FILE_EXTENSION ".b2modmap"
21 #define LIB_FILE_EXTENSION ".so"
22 
23 
25 {
26  static ModuleManager instance;
27  return instance;
28 }
29 
30 
32 {
33  //Only register a module proxy if it was not yet registered.
34  if (m_registeredProxyMap.count(moduleProxy->getModuleName()) == 0) {
35  m_registeredProxyMap.insert(make_pair(moduleProxy->getModuleName(), moduleProxy));
36  } else {
37  B2ERROR("There seems to be more than one module called '" << moduleProxy->getModuleName() <<
38  "'. Since module names are unique, you must rename one of them!");
39  }
40 }
41 
42 
43 void ModuleManager::addModuleSearchPath(const string& path)
44 {
45  if (FileSystem::isDir(path)) {
46  m_moduleSearchPathList.push_back(path);
47 
48  //Search the path for map files and add the contained module names to the known module names
49  auto fullPath = std::filesystem::absolute(std::filesystem::path(path));
50  std::filesystem::directory_iterator endIter;
51 
52 
53  map<string, string> moduleNameLibMap;
54  for (std::filesystem::directory_iterator dirItr(fullPath); dirItr != endIter; ++dirItr) {
55  //Only files in the given folder are taken, subfolders are not used.
56  if (std::filesystem::is_regular_file(dirItr->status())) {
57  if (std::filesystem::path(dirItr->path()).extension() == MAP_FILE_EXTENSION) {
58  fillModuleNameLibMap(moduleNameLibMap, *dirItr);
59  }
60  }
61  }
62  //put modules into central map, if they haven't been added yet
63  m_moduleNameLibMap.insert(moduleNameLibMap.begin(), moduleNameLibMap.end());
64  }
65 }
66 
67 
68 const list<string>& ModuleManager::getModuleSearchPaths() const
69 {
70  return m_moduleSearchPathList;
71 }
72 
73 
74 const map<string, string>& ModuleManager::getAvailableModules() const
75 {
76  return m_moduleNameLibMap;
77 }
78 
79 
80 ModulePtr ModuleManager::registerModule(const string& moduleName, std::string sharedLibPath) noexcept(false)
81 {
82  auto moduleIter = m_registeredProxyMap.find(moduleName);
83 
84  // Print an error message and then raise the exception ...
85  auto error = [&moduleName](const std::string & text) -> void {
86  auto exception = ModuleNotCreatedError() << moduleName << text;
87  B2ERROR(exception.what());
88  throw exception;
89  };
90 
91  //If the proxy of the module was not already registered, load the corresponding shared library first
92  if (moduleIter == m_registeredProxyMap.end()) {
93  // no library specified, try to find it from map of known modules
94  if (sharedLibPath.empty()) {
95  auto libIter = m_moduleNameLibMap.find(moduleName);
96  if (libIter != m_moduleNameLibMap.end()) {
97  sharedLibPath = libIter->second;
98  } else {
99  error("The module is not known to the framework!");
100  }
101  }
102  // Now we have a library name (provided or determined, try to load)
103  if (!FileSystem::isFile(sharedLibPath)) {
104  error("Could not load shared library " + sharedLibPath + ", file does not exist!");
105  }
106  if (!FileSystem::loadLibrary(sharedLibPath)) {
107  error("Could not load shared library " + sharedLibPath + ".");
108  }
109  //Check if the loaded shared library file contained the module
110  moduleIter = m_registeredProxyMap.find(moduleName);
111  if (moduleIter == m_registeredProxyMap.end()) {
112  error("The shared library " + sharedLibPath + " does not contain the module!");
113  }
114  }
115 
116  //Create an instance of the module found or loaded in the previous steps and return it.
117  //The iterator cannot point to the end of the map, we checked in all branches.
118  ModulePtr currModulePtr = moduleIter->second->createModule();
119  m_createdModulesList.push_back(currModulePtr);
120  return currModulePtr;
121 }
122 
123 
125 {
126  return m_createdModulesList;
127 }
128 
129 
130 ModulePtrList ModuleManager::getModulesByProperties(const ModulePtrList& modulePathList, unsigned int propertyFlags)
131 {
132  ModulePtrList tmpModuleList;
133 
134  for (const ModulePtr& module : modulePathList)
135  if (module->hasProperties(propertyFlags)) tmpModuleList.push_back(module);
136 
137  return tmpModuleList;
138 }
139 
140 bool ModuleManager::allModulesHaveFlag(const ModulePtrList& list, unsigned int flag)
141 {
142  for (const auto& m : list) {
143  if (!m->hasProperties(flag))
144  return false;
145  }
146  return true;
147 }
148 
149 
150 //============================================================================
151 // Private methods
152 //============================================================================
153 
154 void ModuleManager::fillModuleNameLibMap(std::map<std::string, std::string>& moduleNameLibMap,
155  const std::filesystem::directory_entry& mapPath)
156 {
157  //Check if the associated shared library file exists
158  string sharedLibPath = std::filesystem::path(mapPath).replace_extension(LIB_FILE_EXTENSION).string();
159  if (!FileSystem::fileExists(sharedLibPath)) {
160  B2WARNING("The shared library file: " << sharedLibPath << " doesn't exist, but is required by " << mapPath.path().string());
161  return;
162  }
163 
164  //Open the map file and parse the content line by line
165  ifstream mapFile(mapPath.path().string().c_str());
166  string currentLine;
167 
168  //Read each line of the map file and use boost regular expression to find the module name string in brackets.
169  std::regex expression("^REG_MODULE\\((.+)\\)$");
170  std::match_results<std::string::const_iterator> matchResult;
171 
172  int lineNr{0};
173  while (getline(mapFile, currentLine)) {
174  ++lineNr;
175 
176  if (!std::regex_match(currentLine, matchResult, expression)) {
177  B2ERROR("Problem parsing map file " << mapPath << ": Invalid entry in line " << lineNr << ", skipping remaining file");
178  return;
179  }
180 
181  string moduleName(matchResult[1].first, matchResult[1].second);
182  //Add result to map
183  if (moduleNameLibMap.count(moduleName) == 0) {
184  moduleNameLibMap.insert(make_pair(moduleName, sharedLibPath));
185  } else {
186  B2ERROR("There seems to be more than one module called '" << moduleName <<
187  "'. Since module names are unique, you must rename one of them!");
188  }
189  }
190 
191  //Close the map file
192  mapFile.close();
193 }
194 
195 ModuleManager::ModuleManager() = default;
196 
198 
200 {
201  m_createdModulesList.clear();
202 }
static bool loadLibrary(std::string library, bool fullname=true)
Load a shared library.
Definition: FileSystem.cc:63
static bool isFile(const std::string &filename)
Check if filename points to an existing file.
Definition: FileSystem.cc:45
static bool isDir(const std::string &filename)
Check if filename points to an existing directory.
Definition: FileSystem.cc:51
static bool fileExists(const std::string &filename)
Check if the file with given filename exists.
Definition: FileSystem.cc:32
The ModuleManager Class.
Definition: ModuleManager.h:53
void registerModuleProxy(ModuleProxyBase *moduleProxy)
Registers a module proxy.
const std::map< std::string, std::string > & getAvailableModules() const
Returns a map of all modules that were found in the module search paths.
const std::list< std::shared_ptr< Module > > & getCreatedModules() const
Returns a reference to the list of created modules.
static std::list< std::shared_ptr< Module > > getModulesByProperties(const std::list< std::shared_ptr< Module > > &modulePathList, unsigned int propertyFlags)
Returns a list of those modules which carry property flags matching the specified ones.
const std::list< std::string > & getModuleSearchPaths() const
Returns a reference to the list of the modules search filepaths.
std::shared_ptr< Module > registerModule(const std::string &moduleName, std::string sharedLibPath="") noexcept(false)
Creates an instance of a module and registers it to the ModuleManager.
static bool allModulesHaveFlag(const std::list< std::shared_ptr< Module >> &list, unsigned int flag)
Returns true if and only if all modules in list have the given flag (or list is empty).
static ModuleManager & Instance()
Exception is thrown if the requested module could not be created by the ModuleManager.
static void fillModuleNameLibMap(std::map< std::string, std::string > &moduleNameLibMap, const std::filesystem::directory_entry &mapPath)
Adds the module names defined in the map file to the list of known module names.
~ModuleManager()
The ModuleManager destructor.
ModuleManager()
The constructor is hidden to avoid that someone creates an instance of this class.
void reset()
Delete all created modules.
void addModuleSearchPath(const std::string &path)
Adds a new filepath to the list of filepaths which are searched for a requested module.
The base module proxy class is used to create new instances of a module.
Definition: Module.h:597
const std::string & getModuleName() const
Returns the module name of the module associated to this proxy.
Definition: Module.h:630
std::shared_ptr< Module > ModulePtr
Defines a pointer to a module object as a boost shared pointer.
Definition: Module.h:40
std::list< ModulePtr > ModulePtrList
Defines a std::list of shared module pointers.
Definition: Module.h:584
Abstract base class for different kinds of events.