| The Gaudi Framework v27r1

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

PluginService.cpp
Go to the documentation of this file.
1 /*****************************************************************************\
2 * (c) Copyright 2013 CERN *
3 * *
4 * This software is distributed under the terms of the GNU General Public *
5 * Licence version 3 (GPL Version 3), copied verbatim in the file "LICENCE". *
6 * *
7 * In applying this licence, CERN does not waive the privileges and immunities *
8 * granted to it by virtue of its status as an Intergovernmental Organization *
9 * or submit itself to any jurisdiction. *
10 \*****************************************************************************/
11
13
14 #include <Gaudi/PluginService.h>
15
16 #include <dlfcn.h>
17 #include <dirent.h>
18
19 #include <cstdlib>
20 #include <iostream>
21 #include <fstream>
22 #include <memory>
23
24 #include <cxxabi.h>
25 #include <sys/stat.h>
26
27 #if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L
28 #define REG_SCOPE_LOCK \
29 std::lock_guard<std::recursive_mutex> _guard(m_mutex);
30
31 namespace {
32 std::mutex registrySingletonMutex;
33 }
34 #define SINGLETON_LOCK \
35 std::lock_guard<std::mutex> _guard(::registrySingletonMutex);
36 #else
37 #define REG_SCOPE_LOCK
38 #define SINGLETON_LOCK
39 #endif
40
41 #include <algorithm>
42
43 namespace {
44 // string trimming functions taken from
45 // http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring
46
47 constexpr struct is_space_t {
48 bool operator()(int i) const { return std::isspace(i); }
49 } is_space {};
50
51 // trim from start
52 static inline std::string &ltrim(std::string &s) {
53 s.erase(s.begin(),
54 std::find_if_not(s.begin(), s.end(), is_space ) );
55 return s;
56 }
57
58 // trim from end
59 static inline std::string &rtrim(std::string &s) {
60 s.erase(std::find_if_not(s.rbegin(), s.rend(), is_space).base(),
61 s.end());
62 return s;
63 }
64 // trim from both ends
65 static inline std::string &trim(std::string &s) {
66 return ltrim(rtrim(s));
67 }
68 }
69
70 namespace {
74 inline void factoryInfoSetHelper(std::string& dest, const std::string value,
75 const std::string& desc,
76 const std::string& id) {
77 if (dest.empty()) {
78 dest = value;
79 } else if (dest != value) {
80 Gaudi::PluginService::Details::logger().warning(
81 "new factory loaded for '" + id + "' with different "
82 + desc + ": " + dest + " != " + value );
83 }
84 }
85
86 struct OldStyleCnv {
87 std::string name;
88 void operator() (const char c) {
89 switch(c) {
90 case '<':
91 case '>':
92 case ',':
93 case '(':
94 case ')':
95 case ':':
96 case '.':
97 name.push_back('_'); break;
98 case '&':
99 name.push_back('r'); break;
100 case '*':
101 name.push_back('p'); break;
102 case ' ': break;
103 default:
104 name.push_back(c); break;
105 }
106 }
107 };
109 std::string old_style_name(const std::string& name) {
110 return std::for_each(name.begin(), name.end(), OldStyleCnv()).name;
111 }
112 }
113
114 namespace Gaudi { namespace PluginService {
115
116 Exception::Exception(std::string msg): m_msg(std::move(msg)) {}
117 Exception::~Exception() throw() {}
118 const char* Exception::what() const throw() {
119 return m_msg.c_str();
120 }
121
122 namespace Details {
123 void* getCreator(const std::string& id, const std::string& type) {
124 return Registry::instance().get(id, type);
125 }
126
127 std::string demangle(const std::string& id) {
128 int status;
129 auto realname = std::unique_ptr<char,decltype(free)*>( abi::__cxa_demangle(id.c_str(), nullptr, nullptr, &status),
130 free );
131 if (!realname) return id;
132 return std::string{realname.get()};
133 }
134 std::string demangle(const std::type_info& id) {
135 return demangle(id.name());
136 }
137
138 Registry& Registry::instance() {
139 SINGLETON_LOCK
140 static Registry r;
141 return r;
142 }
143
144 Registry::Registry(): m_initialized(false) {}
145
146 void Registry::initialize() {
147 REG_SCOPE_LOCK
148 if (m_initialized) return;
149 m_initialized = true;
150 #ifdef WIN32
151 const char* envVar = "PATH";
152 const char sep = ';';
153 #else
154 const char* envVar = "LD_LIBRARY_PATH";
155 const char sep = ':';
156 #endif
157 char *search_path = ::getenv(envVar);
158 if (search_path) {
159 logger().debug(std::string("searching factories in ") + envVar);
160 std::string path(search_path);
161 std::string::size_type pos = 0;
162 std::string::size_type newpos = 0;
163 while (pos != std::string::npos) {
164 std::string dirName;
165 // get the next entry in the path
166 newpos = path.find(sep, pos);
167 if (newpos != std::string::npos) {
168 dirName = path.substr(pos, newpos - pos);
169 pos = newpos+1;
170 } else {
171 dirName = path.substr(pos);
172 pos = newpos;
173 }
174 logger().debug(std::string(" looking into ") + dirName);
175 // look for files called "*.components" in the directory
176 DIR *dir = opendir(dirName.c_str());
177 if (dir) {
178 struct dirent * entry;
179 while ((entry = readdir(dir))) {
180 std::string name(entry->d_name);
181 // check if the file name ends with ".components"
182 std::string::size_type extpos = name.find(".components");
183 if ((extpos != std::string::npos) &&
184 ((extpos+11) == name.size())) {
185 std::string fullPath = (dirName + '/' + name);
186 { // check if it is a regular file
187 struct stat buf;
188 stat(fullPath.c_str(), &buf);
189 if (!S_ISREG(buf.st_mode)) continue;
190 }
191 // read the file
192 logger().debug(std::string(" reading ") + name);
193 std::ifstream factories{fullPath};
194 std::string line;
195 int factoriesCount = 0;
196 int lineCount = 0;
197 while (!factories.eof()) {
198 ++lineCount;
199 std::getline(factories, line);
200 trim(line);
201 // skip empty lines and lines starting with '#'
202 if (line.empty() || line[0] == '#') continue;
203 // look for the separator
204 auto pos = line.find(':');
205 if (pos == std::string::npos) {
206 logger().warning( "failed to parse line "
207 + fullPath + ':'
208 + std::to_string(lineCount) );
209 continue;
210 }
211 const std::string lib(line, 0, pos);
212 const std::string fact(line, pos+1);
213 m_factories.emplace(fact, FactoryInfo(lib));
214 #ifdef GAUDI_REFLEX_COMPONENT_ALIASES
215 // add an alias for the factory using the Reflex convention
216 std::string old_name = old_style_name(fact);
217 if (fact != old_name) {
218 FactoryInfo old_info(lib);
219 old_info.properties["ReflexName"] = "true";
220 m_factories.emplace(old_name, old_info);
221 }
222 #endif
223 ++factoriesCount;
224 }
225 if (logger().level() <= Logger::Debug) {
226 logger().debug( " found " + std::to_string( factoriesCount )
227 + " factories" );
228 }
229 }
230 }
231 closedir(dir);
232 }
233 }
234 }
235 }
236
237 Registry::FactoryInfo&
238 Registry::add(const std::string& id, void *factory,
239 const std::string& type, const std::string& rtype,
240 const std::string& className,
241 const Properties& props){
242 REG_SCOPE_LOCK
243 FactoryMap &facts = factories();
244 auto entry = facts.find(id);
245 if (entry == facts.end())
246 {
247 // this factory was not known yet
248 entry = facts.emplace( id, FactoryInfo("unknown", factory,
249 type, rtype, className, props) ).first;
250 } else {
251 // do not replace an existing factory with a new one
252 if (!entry->second.ptr) entry->second.ptr = factory;
253 factoryInfoSetHelper(entry->second.type, type, "type", id);
254 factoryInfoSetHelper(entry->second.rtype, rtype, "return type", id);
255 factoryInfoSetHelper(entry->second.className, className, "class", id);
256 }
257 #ifdef GAUDI_REFLEX_COMPONENT_ALIASES
258 // add an alias for the factory using the Reflex convention
259 std::string old_name = old_style_name(id);
260 if (id != old_name)
261 add(old_name, factory, type, rtype, className, props)
262 .properties["ReflexName"] = "true";
263 #endif
264 return entry->second;
265 }
266
267 void* Registry::get(const std::string& id, const std::string& type) const {
268 REG_SCOPE_LOCK
269 const FactoryMap &facts = factories();
270 auto f = facts.find(id);
271 if (f != facts.end())
272 {
273 #ifdef GAUDI_REFLEX_COMPONENT_ALIASES
274 const Properties& props = f->second.properties;
275 if (props.find("ReflexName") != props.end())
276 logger().warning("requesting factory via old name '" + id + "'"
277 "use '" + f->second.className + "' instead");
278 #endif
279 if (!f->second.ptr) {
280 if (!dlopen(f->second.library.c_str(), RTLD_LAZY | RTLD_GLOBAL)) {
281 logger().warning("cannot load " + f->second.library +
282 " for factory " + id);
283 char *dlmsg = dlerror();
284 if (dlmsg) logger().warning(dlmsg);
285 return nullptr;
286 }
287 f = facts.find(id); // ensure that the iterator is valid
288 }
289 if (f->second.type == type) return f->second.ptr;
290 logger().warning("found factory " + id + ", but of wrong type: " +
291 demangle(f->second.type) + " instead of " + demangle(type));
292 }
293 return nullptr; // factory not found
294 }
295
296 const Registry::FactoryInfo& Registry::getInfo(const std::string& id) const {
297 REG_SCOPE_LOCK
298 static const FactoryInfo unknown("unknown");
299 const FactoryMap &facts = factories();
300 auto f = facts.find(id);
301 return (f != facts.end()) ? f->second : unknown;
302 }
303
304 Registry&
305 Registry::addProperty(const std::string& id,
306 const std::string& k,
307 const std::string& v) {
308 REG_SCOPE_LOCK
309 FactoryMap &facts = factories();
310 auto f = facts.find(id);
311 if (f != facts.end()) f->second.properties[k] = v;
312 return *this;
313 }
314
315 std::set<Registry::KeyType> Registry::loadedFactories() const {
316 REG_SCOPE_LOCK
317 const FactoryMap &facts = factories();
318 std::set<KeyType> l;
319 for (const auto& f : facts )
320 {
321 if (f.second.ptr) l.insert(f.first);
322 }
323 return l;
324 }
325
326 void Logger::report(Level lvl, const std::string& msg) {
327 static const char* levels[] = {"DEBUG : ",
328 "INFO : ",
329 "WARNING: ",
330 "ERROR : "};
331 if (lvl >= level()) {
332 std::cerr << levels[lvl] << msg << std::endl;
333 }
334 }
335
336 static std::unique_ptr<Logger> s_logger(new Logger);
337 Logger& logger() { return *s_logger; }
338 void setLogger(Logger* logger) { s_logger.reset(logger); }
339
340 } // namespace Details
341
342 void SetDebug(int debugLevel) {
343 using namespace Details;
344 Logger& l = logger();
345 if (debugLevel > 1)
346 l.setLevel(Logger::Debug);
347 else if (debugLevel > 0)
348 l.setLevel(Logger::Info);
349 else l.setLevel(Logger::Warning);
350 }
351
352 int Debug() {
353 using namespace Details;
354 switch (logger().level()) {
355 case Logger::Debug: return 2;
356 case Logger::Info: return 1;
357 default: return 0;
358 }
359 }
360
361 }} // namespace Gaudi::PluginService
Gaudi::PluginService::Details::Logger::Info
Definition: PluginServiceDetails.h:210
Gaudi::PluginService::Exception::~Exception
virtual ~Exception()
Definition: PluginService.cpp:117
std::string::empty
T empty(T...args)
gaudiComponentHelp.name
name
Definition: gaudiComponentHelp.py:28
GaudiMP.FdsRegistry.msg
tuple msg
Definition: FdsRegistry.py:8
Gaudi::PluginService::Details::Registry::getInfo
const FactoryInfo & getInfo(const std::string &id) const
Retrieve the FactoryInfo object for an id.
Definition: PluginService.cpp:296
Gaudi::PluginService::Exception::m_msg
std::string m_msg
Definition: PluginService.h:71
std::string::rend
T rend(T...args)
Gaudi::PluginService::Details::Registry::addProperty
Registry & addProperty(const std::string &id, const std::string &k, const std::string &v)
Add a property to an already existing FactoryInfo object (via its id.)
Definition: PluginService.cpp:305
Gaudi::PluginService::Details::Logger::level
Level level() const
Definition: PluginServiceDetails.h:213
REG_SCOPE_LOCK
#define REG_SCOPE_LOCK
Definition: PluginService.cpp:37
gaudirun.c
tuple c
Definition: gaudirun.py:391
Gaudi::PluginService::Details::Registry::Registry
Registry()
Private constructor for the singleton pattern.
Definition: PluginService.cpp:144
std::getline
T getline(T...args)
std::to_string
T to_string(T...args)
std::endl
T endl(T...args)
std
STL namespace.
Gaudi::PluginService::Details::Registry::initialize
void initialize()
Initialize the registry loading the list of factories from the .component files in the library search...
Definition: PluginService.cpp:146
std::string::end
T end(T...args)
SINGLETON_LOCK
#define SINGLETON_LOCK
Definition: PluginService.cpp:38
Gaudi::PluginService::Details::Registry::FactoryInfo
Definition: PluginServiceDetails.h:106
std::map< KeyType, std::string >
Gaudi::PluginService::Details::Registry::FactoryInfo::properties
Properties properties
Definition: PluginServiceDetails.h:121
Gaudi::PluginService::Details::Registry::loadedFactories
std::set< KeyType > loadedFactories() const
Return a list of all the known and loaded factories.
Definition: PluginService.cpp:315
std::mutex
Gaudi::PluginService::Details::logger
GAUDIPS_API Logger & logger()
Return the current logger instance.
Definition: PluginService.cpp:337
Gaudi::PluginService::Details::Logger
Simple logging class, just to provide a default implementation.
Definition: PluginServiceDetails.h:208
std::type_info
std::string
STL class.
std::string::push_back
T push_back(T...args)
Gaudi::PluginService::SetDebug
GAUDIPS_API void SetDebug(int debugLevel)
Backward compatibility with Reflex.
Definition: PluginService.cpp:342
plotSpeedupsPyRoot.line
tuple line
Definition: plotSpeedupsPyRoot.py:164
gaudirun.type
string type
Definition: gaudirun.py:151
Gaudi::PluginService::Details::Registry::get
void * get(const std::string &id, const std::string &type) const
Retrieve the factory for the given id.
Definition: PluginService.cpp:267
Gaudi::PluginService::Details::demangle
GAUDIPS_API std::string demangle(const std::type_info &id)
Return a canonical name for type_info object (implementation borrowed from GaudiKernel/System).
Definition: PluginService.cpp:134
Gaudi::PluginService::Details::Logger::Level
Level
Definition: PluginServiceDetails.h:210
gaudirun.dest
string dest
Definition: gaudirun.py:162
std::string::erase
T erase(T...args)
Gaudi::PluginService::Exception::Exception
Exception(std::string msg)
Definition: PluginService.cpp:116
Gaudi::PluginService::Details::Registry::factories
const FactoryMap & factories() const
Return the known factories (loading the list if not yet done).
Definition: PluginServiceDetails.h:163
dump_component_properties.value
list value
Definition: dump_component_properties.py:12
Gaudi::PluginService::Details::Logger::report
virtual void report(Level lvl, const std::string &msg)
Definition: PluginService.cpp:326
Gaudi::PluginService::Details::Logger::warning
void warning(const std::string &msg)
Definition: PluginServiceDetails.h:217
Gaudi::Utils::Histos::path
GAUDI_API std::string path(const AIDA::IBaseHistogram *aida)
get the path in THS for AIDA histogram
Definition: HistoTableFormat.cpp:191
gaudirun.l
dictionary l
Definition: gaudirun.py:421
std::set::insert
T insert(T...args)
PluginService.h
std::find_if_not
T find_if_not(T...args)
std::string::size
T size(T...args)
std::set
STL class.
Gaudi::PluginService::Details::getCreator
GAUDIPS_API void * getCreator(const std::string &id, const std::string &type)
Function used to load a specific factory function.
Definition: PluginService.cpp:123
std::unique_ptr
STL class.
Gaudi::PluginService::Details::Logger::Warning
Definition: PluginServiceDetails.h:210
Gaudi::PluginService::Details::Logger::Debug
Definition: PluginServiceDetails.h:210
std::string::begin
T begin(T...args)
std::string::c_str
T c_str(T...args)
Gaudi::PluginService::Details::Registry::instance
static Registry & instance()
Retrieve the singleton instance of Registry.
Definition: PluginService.cpp:138
std::map::emplace
T emplace(T...args)
gaudirun.s
string s
Definition: gaudirun.py:245
Gaudi::PluginService::Details::Registry
In-memory database of the loaded factories.
Definition: PluginServiceDetails.h:99
Gaudi::PluginService::Exception::what
virtual const char * what() const
Definition: PluginService.cpp:118
std::string::substr
T substr(T...args)
Gaudi::PluginService::Details::Registry::add
FactoryInfo & add(const I &id, typename F::FuncType ptr)
Add a factory to the database.
Definition: PluginServiceDetails.h:137
gaudirun.level
level
Definition: gaudirun.py:261
Gaudi::PluginService::Debug
GAUDIPS_API int Debug()
Backward compatibility with Reflex.
Definition: PluginService.cpp:352
Gaudi::PluginService::Details::setLogger
GAUDIPS_API void setLogger(Logger *logger)
Set the logger instance to use.
Definition: PluginService.cpp:338
std::for_each
T for_each(T...args)
ana.i
list i
Definition: ana.py:128
std::cerr
std::isspace
T isspace(T...args)
Gaudi::PluginService::Details::Registry::m_factories
FactoryMap m_factories
Internal storage for factories.
Definition: PluginServiceDetails.h:199
Gaudi
Helper functions to set/get the application return code.
Definition: __init__.py:1
std::ifstream
STL class.
Gaudi::PluginService::Details::Registry::m_initialized
bool m_initialized
Flag recording if the registry has been initialized or not.
Definition: PluginServiceDetails.h:196
Gaudi::PluginService::Details::Logger::debug
void debug(const std::string &msg)
Definition: PluginServiceDetails.h:216
std::string::rbegin
T rbegin(T...args)