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