Belle II Software development
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
17using namespace Belle2;
18using 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
43void 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
68const list<string>& ModuleManager::getModuleSearchPaths() const
69{
71}
72
73
74const map<string, string>& ModuleManager::getAvailableModules() const
75{
76 return m_moduleNameLibMap;
77}
78
79
80ModulePtr 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{
127}
128
129
130ModulePtrList 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
140bool 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
154void 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
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.
std::list< std::shared_ptr< Module > > m_createdModulesList
List of all 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.
std::list< std::string > m_moduleSearchPathList
List of all checked and validated filepaths that are searched for map files.
static ModuleManager & Instance()
Exception is thrown if the requested module could not be created by the ModuleManager.
std::map< std::string, std::string > m_moduleNameLibMap
Maps the module name to the filename of the shared library which containes the module.
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.
std::map< std::string, ModuleProxyBase * > m_registeredProxyMap
Maps the module name to a pointer of its proxy.
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.
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).
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:43
std::list< ModulePtr > ModulePtrList
Defines a std::list of shared module pointers.
Definition: Module.h:584
Abstract base class for different kinds of events.
STL namespace.