| # Gaudi Framework, version v25r0 |

Home |  | Generated: Mon Feb 17 2014

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

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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 // string trimming functions taken from
42 // http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring
43 #include <algorithm>
44 // trim from start
45 static inline std::string &ltrim(std::string &s) {
46 s.erase(s.begin(),
47 std::find_if(s.begin(), s.end(),
48 std::not1(std::ptr_fun<int, int>(std::isspace))));
49 return s;
50 }
51
52 // trim from end
53 static inline std::string &rtrim(std::string &s) {
54 s.erase(std::find_if(s.rbegin(), s.rend(),
55 std::not1(std::ptr_fun<int, int>(std::isspace)))
56 .base(),
57 s.end());
58 return s;
59 }
60 // trim from both ends
61 static inline std::string &trim(std::string &s) {
62 return ltrim(rtrim(s));
63 }
64
65 namespace {
69 inline void factoryInfoSetHelper(std::string& dest, const std::string value,
70 const std::string& desc,
71 const std::string& id) {
72 if (dest.empty()) {
73 dest = value;
74 } else if (dest != value) {
75 std::ostringstream o;
76 o << "new factory loaded for '" << id << "' with different "
77 << desc << ": " << dest << " != " << value;
78 Gaudi::PluginService::Details::logger().warning(o.str());
79 }
80 }
81
82 struct OldStyleCnv {
83 std::string name;
84 void operator() (const char c) {
85 switch(c) {
86 case '<':
87 case '>':
88 case ',':
89 case '(':
90 case ')':
91 case ':':
92 case '.':
93 name.push_back('_'); break;
94 case '&':
95 name.push_back('r'); break;
96 case '*':
97 name.push_back('p'); break;
98 case ' ': break;
99 default:
100 name.push_back(c); break;
101 }
102 }
103 };
105 std::string old_style_name(const std::string& name) {
106 return std::for_each(name.begin(), name.end(), OldStyleCnv()).name;
107 }
108 }
109
110 namespace Gaudi { namespace PluginService {
111
112 Exception::Exception(const std::string& msg): m_msg(msg) {}
113 Exception::~Exception() throw() {}
114 const char* Exception::what() const throw() {
115 return m_msg.c_str();
116 }
117
118 namespace Details {
119 void* getCreator(const std::string& id, const std::string& type) {
120 return Registry::instance().get(id, type);
121 }
122
123 Registry& Registry::instance() {
124 SINGLETON_LOCK
125 static Registry r;
126 return r;
127 }
128
129 Registry::Registry(): m_initialized(false) {}
130
131 void Registry::initialize() {
132 REG_SCOPE_LOCK
133 if (m_initialized) return;
134 m_initialized = true;
135 #ifdef WIN32
136 const char* envVar = "PATH";
137 const char sep = ';';
138 #else
139 const char* envVar = "LD_LIBRARY_PATH";
140 const char sep = ':';
141 #endif
142 char *search_path = ::getenv(envVar);
143 if (search_path) {
144 logger().debug(std::string("searching factories in ") + envVar);
145 std::string path(search_path);
146 std::string::size_type pos = 0;
147 std::string::size_type newpos = 0;
148 while (pos != std::string::npos) {
149 std::string dirName;
150 // get the next entry in the path
151 newpos = path.find(sep, pos);
152 if (newpos != std::string::npos) {
153 dirName = path.substr(pos, newpos - pos);
154 pos = newpos+1;
155 } else {
156 dirName = path.substr(pos);
157 pos = newpos;
158 }
159 logger().debug(std::string(" looking into ") + dirName);
160 // look for files called "*.components" in the directory
161 DIR *dir = opendir(dirName.c_str());
162 if (dir) {
163 struct dirent * entry;
164 while ((entry = readdir(dir))) {
165 std::string name(entry->d_name);
166 // check if the file name ends with ".components"
167 std::string::size_type extpos = name.find(".components");
168 if ((extpos != std::string::npos) &&
169 ((extpos+11) == name.size())) {
170 std::string fullPath = (dirName + '/' + name);
171 { // check if it is a regular file
172 struct stat buf;
173 stat(fullPath.c_str(), &buf);
174 if (!S_ISREG(buf.st_mode)) continue;
175 }
176 // read the file
177 logger().debug(std::string(" reading ") + name);
178 std::ifstream factories(fullPath.c_str());
179 std::string line;
180 int factoriesCount = 0;
181 int lineCount = 0;
182 while (!factories.eof()) {
183 ++lineCount;
184 std::getline(factories, line);
185 trim(line);
186 // skip empty lines and lines starting with '#'
187 if (line.empty() || line[0] == '#') continue;
188 // look for the separator
189 std::string::size_type pos = line.find(':');
190 if (pos == std::string::npos) {
191 std::ostringstream o;
192 o << "failed to parse line " << fullPath
193 << ':' << lineCount;
194 logger().warning(o.str());
195 continue;
196 }
197 const std::string lib(line, 0, pos);
198 const std::string fact(line, pos+1);
199 m_factories.insert(std::make_pair(fact, FactoryInfo(lib)));
200 #ifdef GAUDI_REFLEX_COMPONENT_ALIASES
201 // add an alias for the factory using the Reflex convention
202 std::string old_name = old_style_name(fact);
203 if (fact != old_name) {
204 FactoryInfo old_info(lib);
205 old_info.properties["ReflexName"] = "true";
206 m_factories.insert(std::make_pair(old_name, old_info));
207 }
208 #endif
209 ++factoriesCount;
210 }
211 if (logger().level() <= Logger::Debug) {
212 std::ostringstream o;
213 o << " found " << factoriesCount << " factories";
214 logger().debug(o.str());
215 }
216 }
217 }
218 closedir(dir);
219 }
220 }
221 }
222 }
223
224 Registry::FactoryInfo&
225 Registry::add(const std::string& id, void *factory,
226 const std::string& type, const std::string& rtype,
227 const std::string& className,
228 const Properties& props){
229 REG_SCOPE_LOCK
230 FactoryMap &facts = factories();
231 FactoryMap::iterator entry = facts.find(id);
232 if (entry == facts.end())
233 {
234 // this factory was not known yet
235 entry = facts.insert(std::make_pair(id,
236 FactoryInfo("unknown", factory,
237 type, rtype, className, props))).first;
238 } else {
239 // do not replace an existing factory with a new one
240 if (!entry->second.ptr) {
241 entry->second.ptr = factory;
242 }
243 factoryInfoSetHelper(entry->second.type, type, "type", id);
244 factoryInfoSetHelper(entry->second.rtype, rtype, "return type", id);
245 factoryInfoSetHelper(entry->second.className, className, "class", id);
246 }
247 #ifdef GAUDI_REFLEX_COMPONENT_ALIASES
248 // add an alias for the factory using the Reflex convention
249 std::string old_name = old_style_name(id);
250 if (id != old_name)
251 add(old_name, factory, type, rtype, className, props)
252 .properties["ReflexName"] = "true";
253 #endif
254 return entry->second;
255 }
256
257 void* Registry::get(const std::string& id, const std::string& type) const {
258 REG_SCOPE_LOCK
259 const FactoryMap &facts = factories();
260 FactoryMap::const_iterator f = facts.find(id);
261 if (f != facts.end())
262 {
263 #ifdef GAUDI_REFLEX_COMPONENT_ALIASES
264 const Properties& props = f->second.properties;
265 if (props.find("ReflexName") != props.end())
266 logger().warning("requesting factory via old name '" + id + "'"
267 "use '" + f->second.className + "' instead");
268 #endif
269 if (!f->second.ptr) {
270 if (!dlopen(f->second.library.c_str(), RTLD_LAZY | RTLD_GLOBAL)) {
271 logger().warning("cannot load " + f->second.library +
272 " for factory " + id);
273 char *dlmsg = dlerror();
274 if (dlmsg)
275 logger().warning(dlmsg);
276 return 0;
277 }
278 f = facts.find(id); // ensure that the iterator is valid
279 }
280 if (f->second.type == type) {
281 return f->second.ptr;
282 } else {
283 logger().warning("found factory " + id + ", but of wrong type: " +
284 f->second.type + " instead of " + type);
285 }
286 }
287 return 0; // factory not found
288 }
289
290 const Registry::FactoryInfo& Registry::getInfo(const std::string& id) const {
291 REG_SCOPE_LOCK
292 static FactoryInfo unknown("unknown");
293 const FactoryMap &facts = factories();
294 FactoryMap::const_iterator f = facts.find(id);
295 if (f != facts.end())
296 {
297 return f->second;
298 }
299 return unknown; // factory not found
300 }
301
302 Registry&
303 Registry::addProperty(const std::string& id,
304 const std::string& k,
305 const std::string& v) {
306 REG_SCOPE_LOCK
307 FactoryMap &facts = factories();
308 FactoryMap::iterator f = facts.find(id);
309 if (f != facts.end())
310 {
311 f->second.properties[k] = v;
312 }
313 return *this;
314 }
315
316 std::set<Registry::KeyType> Registry::loadedFactories() const {
317 REG_SCOPE_LOCK
318 const FactoryMap &facts = factories();
319 std::set<KeyType> l;
320 for (FactoryMap::const_iterator f = facts.begin();
321 f != facts.end(); ++f)
322 {
323 if (f->second.ptr)
324 l.insert(f->first);
325 }
326 return l;
327 }
328
329 std::string demangle(const std::type_info& id) {
330 int status;
331 char* realname;
332 realname = abi::__cxa_demangle(id.name(), 0, 0, &status);
333 if (realname == 0) return id.name();
334 std::string result(realname);
335 free(realname);
336 return result;
337 }
338
339 void Logger::report(Level lvl, const std::string& msg) {
340 static const char* levels[] = {"DEBUG : ",
341 "INFO : ",
342 "WARNING: ",
343 "ERROR : "};
344 if (lvl >= level()) {
345 std::cerr << levels[lvl] << msg << std::endl;
346 }
347 }
348
349 static std::auto_ptr<Logger> s_logger(new Logger);
350 Logger& logger() {
351 return *s_logger;
352 }
353 void setLogger(Logger* logger) {
354 s_logger.reset(logger);
355 }
356
357 } // namespace Details
358
359 void SetDebug(int debugLevel) {
360 using namespace Details;
361 Logger& l = logger();
362 if (debugLevel > 1)
363 l.setLevel(Logger::Debug);
364 else if (debugLevel > 0)
365 l.setLevel(Logger::Info);
366 else l.setLevel(Logger::Warning);
367 }
368
369 int Debug() {
370 using namespace Details;
371 switch (logger().level()) {
372 case Logger::Debug: return 2; break;
373 case Logger::Info: return 1; break;
374 default: return 0;
375 }
376 }
377
378 }} // namespace Gaudi::PluginService