ATLAS Offline Software
Loading...
Searching...
No Matches
ClassIDSvc.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include <fstream>
6#include <iostream>
7#include <iterator>
8#include <boost/algorithm/string/trim.hpp>
9#include <boost/algorithm/string/split.hpp>
10
11#include "GaudiKernel/IIncidentSvc.h"
12#include "GaudiKernel/Incident.h"
13#include "GaudiKernel/ModuleIncident.h"
14#include "GaudiKernel/System.h"
15#include "GaudiKernel/MsgStream.h"
16#include "GaudiKernel/ServiceHandle.h"
20
21#include "ClassIDSvc.h"
22
23namespace {
24 bool tryNumeric (const std::string& s, CLID& clid)
25 {
26 clid = CLID_NULL;
27 char* endptr = nullptr;
28 clid = strtol (s.c_str(), &endptr, 10);
29 return clid != CLID_NULL && endptr == (s.c_str() + s.size());
30 }
31
32
33// HACK LIFTED FROM AthenaBaseComps/AthMsgStreamMacros.h to remove dep loop
34#define ATH_MSG_LVL(lvl, x) \
35 do { \
36 if (msgLevel(lvl)) { \
37 msgStream(lvl) << x << endmsg; \
38 } \
39 } while (0)
40
41#define ATH_MSG_VERBOSE(x) ATH_MSG_LVL(MSG::VERBOSE, x)
42#define ATH_MSG_DEBUG(x) ATH_MSG_LVL(MSG::DEBUG, x)
43#define ATH_MSG_INFO(x) ATH_MSG_LVL(MSG::INFO, x)
44#define ATH_MSG_WARNING(x) ATH_MSG_LVL(MSG::WARNING, x)
45#define ATH_MSG_ERROR(x) ATH_MSG_LVL(MSG::ERROR, x)
46
47#define ATH_CONST_MSG_VERBOSE(x) \
48 do { \
49 if (msgLevel(MSG::VERBOSE)) { \
50 verbose() << x << endmsg; \
51 } \
52 } while (0)
53
54}
55
56
59CLID
61 lock_t lock (m_mutex);
64 while (valid <= CLIDdetail::MAXCLID &&
65 m_clidMap.find(valid) != m_clidMap.end())
66 {
67 ++valid;
68 }
69
70 if (valid > CLIDdetail::MAXCLID) {
71 throw std::runtime_error("ClassIDSvc::nextAvailableID: none in range");
72 }
73
74 return valid;
75}
76
77
78bool
79ClassIDSvc::isIDInUse(const CLID& id ) const {
80 lock_t lock (m_mutex);
82 return m_clidMap.find(id) != m_clidMap.end();
83}
84
85
86bool
87ClassIDSvc::isNameInUse(const std::string& name ) const {
88 lock_t lock (m_mutex);
90 return m_nameMap.find(name) != m_nameMap.end();
91}
92
93
95StatusCode
96ClassIDSvc::getTypeNameOfID(const CLID& id, std::string& typeName) const
97{
98 lock_t lock (m_mutex);
100
101 CLIDMap::const_iterator iID = m_clidMap.find(id);
102 if (iID != m_clidMap.end()) {
103 typeName = iID->second.first;
104 ATH_CONST_MSG_VERBOSE( "getTypeNameOfID(" << id << ") type name is " << typeName );
105 return StatusCode::SUCCESS;
106 }
107 else {
108 ATH_CONST_MSG_VERBOSE( "getTypeNameOfID(" << id << ") no associated type name found" );
109 return StatusCode::FAILURE;
110 }
111}
112
113
115StatusCode
116ClassIDSvc::getTypeInfoNameOfID(const CLID& id, std::string& typeInfoName) const
117{
118 lock_t lock (m_mutex);
119 maybeRescan();
120
121 CLIDMap::const_iterator iID = m_clidMap.find(id);
122 if (iID != m_clidMap.end()) {
123 typeInfoName = iID->second.second;
124 ATH_CONST_MSG_VERBOSE( "getTypeInfoNameOfID(" << id <<
125 ") type-info name is " << typeInfoName );
126 return StatusCode::SUCCESS;
127 }
128 else {
129 ATH_CONST_MSG_VERBOSE( "getTypeInfoNameOfID(" << id <<
130 ") no associated type-info name found" );
131 return StatusCode::FAILURE;
132 }
133}
134
135
137StatusCode
138ClassIDSvc::getIDOfTypeName(const std::string& typeName, CLID& id) const
139{
140 lock_t lock (m_mutex);
141 maybeRescan();
142
143 NameMap::const_iterator iID = m_nameMap.find(typeName);
144 if (iID != m_nameMap.end()) {
145 id = iID->second;
146 ATH_CONST_MSG_VERBOSE( "getIDOfTypeName(" << typeName << ") CLID is " << id );
147 return StatusCode::SUCCESS;
148 }
149 else if (tryNumeric (typeName, id)) {
150 ATH_CONST_MSG_VERBOSE( "getIDOfTypeName(" << typeName << ") is a numeric CLID" );
151 return StatusCode::SUCCESS;
152 }
153 else {
154 ATH_CONST_MSG_VERBOSE( "getIDOfTypeName(" << typeName << ") no associated CLID found" );
155 return StatusCode::FAILURE;
156 }
157}
158
159
161StatusCode
162ClassIDSvc::getIDOfTypeInfoName(const std::string& typeInfoName,
163 CLID& id) const
164{
165 lock_t lock (m_mutex);
166 maybeRescan();
167 NameMap::const_iterator iID = m_tiNameMap.find(typeInfoName);
168 if (iID != m_tiNameMap.end()) {
169 id = iID->second;
170 ATH_CONST_MSG_VERBOSE( "getIDOfTypeInfoName(" << typeInfoName << ") CLID is " << id );
171 return StatusCode::SUCCESS;
172 }
173 else {
174 ATH_CONST_MSG_VERBOSE( "getIDOfTypeInfoName(" << typeInfoName << ") no associated CLID found" );
175 return StatusCode::FAILURE;
176 }
177}
178
179
181StatusCode
183 const std::string& typeName,
184 const std::string& typeInfoName)
185{
186 lock_t lock (m_mutex);
187 if (id < CLIDdetail::MINCLID || id > CLIDdetail::MAXCLID) {
188 ATH_MSG_ERROR( "setTypeNameForID: input id " << id
189 << " is out of allowed range " << CLIDdetail::MINCLID
190 << " : " << CLIDdetail::MAXCLID );
191 return StatusCode::FAILURE;
192 }
193 return uncheckedSetTypePackageForID(id, typeName, typeInfoName);
194}
195
196
197void
199{
200 lock_t lock (m_mutex);
201 ATH_MSG_INFO( "dump: in memory" );
202
203 for (CLID clid : sortedIDs()) {
204 auto it = m_clidMap.find (clid);
205 if (it == m_clidMap.end()) {
206 ATH_MSG_INFO( "CLID: "<< clid << " - type name: NOT FOUND" );
207 }
208 else {
209 ATH_MSG_INFO( "CLID: "<< clid << " - type name: " << it->second.first );
210 }
211 }
212 ATH_MSG_INFO( "------------------------------" );
213}
214
215
216StatusCode
218{
219 ATH_MSG_VERBOSE( "Initializing " << name() ) ;
220
221 CHECK( Service::initialize() );
222
223 // set up the incident service:
224 ServiceHandle<IIncidentSvc> pIncSvc ("IncidentSvc", name());
225 CHECK( pIncSvc.retrieve() );
226
227 pIncSvc->addListener(this, ModuleLoadedIncident::TYPE(), /*priority*/ 100);
228 pIncSvc->release();
229
230 CHECK( maybeRescan() ); // calls fillDB() if not already done
231
232 return StatusCode::SUCCESS;
233}
234
235
236StatusCode
238 ATH_MSG_INFO( "RE-initializing " << name() ) ;
239 CHECK( fillDB() );
240 return StatusCode::SUCCESS;
241}
242
243
244StatusCode
246{
247 if (m_outputFileName != "NULL") {
248 std::ofstream outfile( m_outputFileName );
249 if ( !outfile ) {
250 ATH_MSG_ERROR( "unable to open output CLIDDB file: " << m_outputFileName );
251 return StatusCode::RECOVERABLE;
252 } else {
253 for (CLID clid : sortedIDs()) {
254 const std::string& typeName = m_clidMap[clid].first;
255 const std::string& tiName = m_clidMap[clid].second;
256 outfile << clid << "; " << typeName << "; " << tiName << std::endl;
257 }
258 ATH_MSG_INFO( "finalize: wrote " << m_clidMap.size() <<
259 " entries to output CLIDDB file: " << m_outputFileName );
260 }
261 }
262 return Service::finalize();
263}
264
265
266void ClassIDSvc::handle(const Incident &inc)
267{
268 lock_t lock (m_mutex);
269 const ModuleLoadedIncident& modInc(dynamic_cast<const ModuleLoadedIncident&>(inc));
270
271 getRegistryEntries(modInc.module());
272}
273
274
276ClassIDSvc::ClassIDSvc(const std::string& name,ISvcLocator* svc)
277 : base_class(name,svc),
278 m_clidDBPath(System::getEnv("DATAPATH"))
279{
280}
281
282
283// Return all registered IDs in sorted order.
284std::vector<CLID> ClassIDSvc::sortedIDs() const
285{
286 std::vector<CLID> ids;
287 ids.reserve (m_clidMap.size());
288 for (const auto& p : m_clidMap) {
289 ids.push_back (p.first);
290 }
291 std::sort (ids.begin(), ids.end());
292 return ids;
293}
294
295
297StatusCode
299 bool allOK(true);
300 for (const std::string& DBFile : m_DBFiles) {
301 DirSearchPath::path clidDB(DBFile);
302
303 if (clidDB.is_absolute()) {
304 allOK = processCLIDDB(clidDB.string());
305 } else {
306 std::list<DirSearchPath::path> paths(m_clidDBPath.find_all(clidDB));
307 if (paths.empty()) {
308 ATH_MSG_DEBUG( "Could not resolve clid DB path " << clidDB
309 << " using DATAPATH. Skipping it." );
310 } else {
311 for (const auto& p : paths) {
312 allOK &= processCLIDDB(p.string());
313 }
314 }
315 }
316 }
317 return StatusCode(allOK);
318}
319
320
321bool
322ClassIDSvc::processCLIDDB(const std::string& fileName)
323{
324 std::ifstream ifile(fileName);
325 if (!ifile) {
326 ATH_MSG_WARNING( "processCLIDDB: unable to open " << fileName );
327 return true;
328 }
329
330 bool allOK(true);
331 unsigned int newEntries(0);
332 std::string line;
333 // Format: CLID;typeName[;typeInfoName]
334 while (allOK && std::getline(ifile, line)) {
335 std::vector<std::string> columns;
336 boost::split(columns, line, boost::is_any_of(";"));
337 long id(-1);
338 if (columns.size()>=2) {
339 boost::trim(columns[0]);
340 try {
341 id = std::stol(columns[0]);
342 } catch (const std::logic_error& e) {
343 ATH_MSG_ERROR( "processCLIDDB: Can't cast ["<< columns[0] << "] to long (clid): " << e.what() );
344 allOK = false;
345 }
346
347 if (uncheckedSetTypePackageForID(id, columns[1],
348 columns.size()>2 ? columns[2] : "")) {
349 ++newEntries;
350 }
351 }
352 }
353
354 if (!allOK) {
355 ATH_MSG_ERROR( "processCLIDDB: processing record '" << line
356 << "' from CLIDDB file: " << fileName );
357 } else {
358 ATH_MSG_DEBUG( "processCLIDDB: read " << newEntries <<
359 " entries from CLIDDB file: " << fileName );
360 }
361
362 return allOK;
363}
364
365
366bool ClassIDSvc::getRegistryEntries(const std::string& moduleName)
367{
368 //not only this is fast, but is necessary to prevent recursion
369 if (!CLIDRegistry::hasNewEntries()) return true;
370
371 bool allOK(true);
372 size_t newEntries(0);
373 //to speed up processing we only take entries added to CLIDRegistry
374 //since last call (thanks Niels!)
375 for (const auto& [clid, typeName, typeInfoName] : CLIDRegistry::newEntries()) {
376 ATH_MSG_VERBOSE( "reading [" << clid << ", " << typeName << ", " << typeInfoName << "]" );
377 if (uncheckedSetTypePackageForID(clid, typeName, typeInfoName)) {
378 ++newEntries;
379 }
380 else {
381 allOK = false;
382 }
383 }
384
385 if (allOK) {
386 ATH_MSG_INFO( "getRegistryEntries: read " << newEntries
387 << " CLIDRegistry entries for module " << moduleName );
388 } else {
389 ATH_MSG_ERROR("getRegistryEntries: can not read CLIDRegistry entries for module "
390 << moduleName );
391 }
392
393 return allOK;
394}
395
396
397StatusCode
399 const std::string& typeName,
400 const std::string& typeInfoName)
401{
402 // process "raw" typeName
403 std::string procName(typeName);
404 boost::trim(procName);
405
406 if (procName.empty()) {
407 ATH_MSG_ERROR( "Empty type name for CLID " << id );
408 return StatusCode::FAILURE;
409 }
410
411 // assign typeInfoName
412 std::string procTiName;
413 if (typeInfoName.empty()) {
414 procTiName = procName;
415 }
416 else {
417 procTiName = typeInfoName;
418 boost::trim(procTiName);
419 }
420
421 // insert into CLID map
422 const auto& [clid_it, clid_success] = m_clidMap.try_emplace(id, procName, procTiName);
423 if (!clid_success && clid_it->second!=std::make_pair(procName,procTiName)) {
424 ATH_MSG_ERROR( "Cannot set type " << std::make_pair(procName,procTiName) << " for CLID " <<
425 id << ": known type for this ID " << clid_it->second );
426 return StatusCode::FAILURE;
427 }
428
429 // insert into type name map
430 const auto& [name_it, name_success] = m_nameMap.try_emplace(procName, id);
431 if (!name_success && name_it->second!=id) {
432 ATH_MSG_ERROR( "Cannot set CLID " << id << " for type name '"
433 << procName << "': known CLID for this name " << name_it->second );
434 return StatusCode::FAILURE;
435 }
436
437 // insert into typeInfo map
438 const auto& [info_it, info_success] = m_tiNameMap.try_emplace(procTiName, id);
439 if (!info_success && info_it->second!=id) {
440 ATH_MSG_ERROR( "Cannot set CLID " << id << " for type-info name '"
441 << procTiName << "' and type '" << procName
442 << "': known CLID for this type-info name " << info_it->second );
443 return StatusCode::FAILURE;
444 }
445
446 ATH_MSG_VERBOSE( "Set type name '" << procName << "' for CLID " << id <<
447 " with type-info name '" << procTiName << "'" );
448
449 return StatusCode::SUCCESS;
450}
451
452
454{
455 // thread-safe because calls are protected by mutex or during initialize
456 ClassIDSvc* nc ATLAS_THREAD_SAFE = const_cast<ClassIDSvc*>(this);
457
458 // read CLID database in case initialize() was not called yet (ATR-23634)
459 [[maybe_unused]] static bool fillDB ATLAS_THREAD_SAFE = nc->fillDB().isSuccess();
460
461 // make sure registry is up-to-date
462 bool status = nc->getRegistryEntries ("ALL");
463
464 return status && fillDB;
465}
466
467
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
a static registry of CLID->typeName entries.
#define ATH_CONST_MSG_VERBOSE(x)
a service to manage and verify CLID assignments in athena
Helpers for checking error return status codes and reporting errors.
#define CHECK(...)
Evaluate an expression and check for errors.
uint32_t CLID
The Class ID type.
Define macros for attributes used to control the static checker.
#define ATLAS_THREAD_SAFE
static bool hasNewEntries()
registry accessors (used by ClassIDSvc)
static CLIDVector_t newEntries()
returns an iterator range over the entries added since last time newEntries was called
virtual StatusCode initialize() override
Gaudi Service Implementation.
StatusCode fillDB()
get clids from CLIDDB and from registry entries
NameMap m_tiNameMap
Definition ClassIDSvc.h:126
Gaudi::Property< std::vector< std::string > > m_DBFiles
Definition ClassIDSvc.h:117
bool processCLIDDB(const std::string &fileName)
load clid/names from a "db" file
virtual StatusCode reinitialize() override
CLIDMap m_clidMap
Definition ClassIDSvc.h:124
void handle(const Incident &inc) override
implement IIncidentListener
Gaudi::Property< std::string > m_outputFileName
Definition ClassIDSvc.h:121
virtual CLID nextAvailableID() const override
get next available CLID
void dump() const
dump to MsgStream contents of in memory DB
StatusCode uncheckedSetTypePackageForID(const CLID &id, const std::string &typeName, const std::string &typeInfoName)
associate type name with clID w/o checking CLID range
virtual StatusCode getIDOfTypeInfoName(const std::string &typeInfoName, CLID &id) const override
get id associated with type-info name (if any)
bool getRegistryEntries(const std::string &moduleName)
load clid/names from a DLL registry
std::vector< CLID > sortedIDs() const
Return all registered IDs in sorted order.
virtual bool isNameInUse(const std::string &name) const override
check if id is used
virtual StatusCode finalize() override
dump CLIDmap to outputFileName;
virtual StatusCode getTypeNameOfID(const CLID &id, std::string &typeName) const override
get type name associated with clID (if any)
virtual StatusCode getTypeInfoNameOfID(const CLID &id, std::string &typeInfoName) const override
get user assigned type-info name associated with clID
virtual bool isIDInUse(const CLID &id) const override
check if id is used
DirSearchPath m_clidDBPath
The path is which clid db files are to be searched (DATAPATH)
Definition ClassIDSvc.h:129
bool maybeRescan() const
Test to see if anything new has been added to the registry.
virtual StatusCode getIDOfTypeName(const std::string &typeName, CLID &id) const override
get id associated with type name (if any)
std::lock_guard< mutex_t > lock_t
Definition ClassIDSvc.h:133
ClassIDSvc(const std::string &name, ISvcLocator *svc)
Standard Constructor.
mutex_t m_mutex
Definition ClassIDSvc.h:134
NameMap m_nameMap
Definition ClassIDSvc.h:125
virtual StatusCode setTypeForID(const CLID &id, const std::string &typeName, const std::string &typeInfoName="") override
associate type name, package info and type-info name with clID
const unsigned long MINCLID
const unsigned long MAXCLID
2**31 - 1
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.