ATLAS Offline Software
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 
23 namespace {
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 
59 CLID
62  maybeRescan();
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 
78 bool
79 ClassIDSvc::isIDInUse(const CLID& id ) const {
81  maybeRescan();
82  return m_clidMap.find(id) != m_clidMap.end();
83 }
84 
85 
86 bool
87 ClassIDSvc::isNameInUse(const std::string& name ) const {
89  maybeRescan();
90  return m_nameMap.find(name) != m_nameMap.end();
91 }
92 
93 
96 ClassIDSvc::getTypeNameOfID(const CLID& id, std::string& typeName) const
97 {
99  maybeRescan();
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 
115 StatusCode
116 ClassIDSvc::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 
137 StatusCode
138 ClassIDSvc::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 
161 StatusCode
162 ClassIDSvc::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 
181 StatusCode
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 
197 void
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 
216 StatusCode
218 {
219  ATH_MSG_VERBOSE( "Initializing " << name() ) ;
220 
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 
238  ATH_MSG_INFO( "RE-initializing " << name() ) ;
239  CHECK( fillDB() );
240  return StatusCode::SUCCESS;
241 }
242 
243 
244 StatusCode
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 
266 void 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 
276 ClassIDSvc::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.
284 std::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 
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 
321 bool
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 
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 
366 bool 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 
397 StatusCode
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 
AllowedVariables::e
e
Definition: AsgElectronSelectorTool.cxx:37
python.tests.PyTestsLib.finalize
def finalize(self)
_info( "content of StoreGate..." ) self.sg.dump()
Definition: PyTestsLib.py:50
CLIDRegistry::newEntries
static CLIDVector_t newEntries()
returns an iterator range over the entries added since last time newEntries was called
Definition: CLIDRegistry.cxx:117
athena.path
path
python interpreter configuration --------------------------------------—
Definition: athena.py:128
CLIDdetail::MINCLID
const unsigned long MINCLID
Definition: CLIDRegistry.h:24
ClassIDSvc::getTypeInfoNameOfID
virtual StatusCode getTypeInfoNameOfID(const CLID &id, std::string &typeInfoName) const override
get user assigned type-info name associated with clID
Definition: ClassIDSvc.cxx:116
ClassIDSvc::m_nameMap
NameMap m_nameMap
Definition: ClassIDSvc.h:125
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: ClassIDSvc.cxx:41
initialize
void initialize()
Definition: run_EoverP.cxx:894
ClassIDSvc::isIDInUse
virtual bool isIDInUse(const CLID &id) const override
check if id is used
Definition: ClassIDSvc.cxx:79
skel.it
it
Definition: skel.GENtoEVGEN.py:407
ClassIDSvc::m_mutex
mutex_t m_mutex
Definition: ClassIDSvc.h:134
python.RatesEmulationExample.lock
lock
Definition: RatesEmulationExample.py:148
CLIDdetail::MAXCLID
const unsigned long MAXCLID
2**31 - 1
Definition: CLIDRegistry.h:25
ClassIDSvc::fillDB
StatusCode fillDB()
get clids from CLIDDB and from registry entries
Definition: ClassIDSvc.cxx:298
ClassIDSvc::dump
void dump() const
dump to MsgStream contents of in memory DB
Definition: ClassIDSvc.cxx:198
dq_defect_bulk_create_defects.line
line
Definition: dq_defect_bulk_create_defects.py:27
ClassIDSvc::m_tiNameMap
NameMap m_tiNameMap
Definition: ClassIDSvc.h:126
ATH_CONST_MSG_VERBOSE
#define ATH_CONST_MSG_VERBOSE(x)
Definition: ClassIDSvc.cxx:47
ClassIDSvc::handle
void handle(const Incident &inc) override
implement IIncidentListener
Definition: ClassIDSvc.cxx:266
ClassIDSvc::finalize
virtual StatusCode finalize() override
dump CLIDmap to outputFileName;
Definition: ClassIDSvc.cxx:245
ClassIDSvc::m_clidDBPath
DirSearchPath m_clidDBPath
The path is which clid db files are to be searched (DATAPATH)
Definition: ClassIDSvc.h:129
calibdata.valid
list valid
Definition: calibdata.py:44
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:209
runITkAlign.DBFile
string DBFile
Definition: runITkAlign.py:112
ClassIDSvc::getTypeNameOfID
virtual StatusCode getTypeNameOfID(const CLID &id, std::string &typeName) const override
get type name associated with clID (if any)
Definition: ClassIDSvc.cxx:96
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: ClassIDSvc.cxx:42
ClassIDSvc::initialize
virtual StatusCode initialize() override
Gaudi Service Implementation.
Definition: ClassIDSvc.cxx:217
CLIDRegistry::hasNewEntries
static bool hasNewEntries()
registry accessors (used by ClassIDSvc)
Definition: CLIDRegistry.cxx:111
ClassIDSvc::setTypeForID
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
Definition: ClassIDSvc.cxx:182
CHECK
#define CHECK(...)
Evaluate an expression and check for errors.
Definition: Control/AthenaKernel/AthenaKernel/errorcheck.h:422
ClassIDSvc::isNameInUse
virtual bool isNameInUse(const std::string &name) const override
check if id is used
Definition: ClassIDSvc.cxx:87
Handler::svc
AthROOTErrorHandlerSvc * svc
Definition: AthROOTErrorHandlerSvc.cxx:10
ClassIDSvc::getRegistryEntries
bool getRegistryEntries(const std::string &moduleName)
load clid/names from a DLL registry
Definition: ClassIDSvc.cxx:366
ClassIDSvc::processCLIDDB
bool processCLIDDB(const std::string &fileName)
load clid/names from a "db" file
Definition: ClassIDSvc.cxx:322
CLID
uint32_t CLID
The Class ID type.
Definition: Event/xAOD/xAODCore/xAODCore/ClassID_traits.h:47
ClassIDSvc::reinitialize
virtual StatusCode reinitialize() override
Definition: ClassIDSvc.cxx:237
TYPE
#define TYPE(CODE, TYP, IOTYP)
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: ClassIDSvc.cxx:43
id
SG::auxid_t id
Definition: Control/AthContainers/Root/debug.cxx:239
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
python.subdetectors.mmg.ids
ids
Definition: mmg.py:8
errorcheck.h
Helpers for checking error return status codes and reporting errors.
ClassIDSvc::ClassIDSvc
ClassIDSvc(const std::string &name, ISvcLocator *svc)
Standard Constructor.
Definition: ClassIDSvc.cxx:276
ClassIDSvc::sortedIDs
std::vector< CLID > sortedIDs() const
Return all registered IDs in sorted order.
Definition: ClassIDSvc.cxx:284
ClassIDSvc::maybeRescan
bool maybeRescan() const
Test to see if anything new has been added to the registry.
Definition: ClassIDSvc.cxx:453
ClassIDSvc::m_clidMap
CLIDMap m_clidMap
Definition: ClassIDSvc.h:124
CLIDRegistry.h
a static registry of CLID->typeName entries. NOT for general use. Use ClassIDSvc instead.
python.TriggerAPI.TriggerAPISession.columns
columns
Definition: TriggerAPISession.py:432
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: ClassIDSvc.cxx:44
ClassIDSvc::uncheckedSetTypePackageForID
StatusCode uncheckedSetTypePackageForID(const CLID &id, const std::string &typeName, const std::string &typeInfoName)
associate type name with clID w/o checking CLID range
Definition: ClassIDSvc.cxx:398
ClassIDSvc::m_outputFileName
Gaudi::Property< std::string > m_outputFileName
Definition: ClassIDSvc.h:121
GRLStrUtil::trim
void trim(std::string &input)
Definition: StrUtil.cxx:12
python.SystemOfUnits.s
float s
Definition: SystemOfUnits.py:147
ReadCalibFromCool.typeName
typeName
Definition: ReadCalibFromCool.py:477
merge.status
status
Definition: merge.py:16
ClassIDSvc
a service to manage and verify CLID assignments in athena.
Definition: ClassIDSvc.h:37
ClassIDSvc::nextAvailableID
virtual CLID nextAvailableID() const override
get next available CLID
Definition: ClassIDSvc.cxx:60
LArCellNtuple.ifile
string ifile
Definition: LArCellNtuple.py:133
ATLAS_THREAD_SAFE
#define ATLAS_THREAD_SAFE
Definition: checker_macros.h:211
ClassIDSvc::getIDOfTypeName
virtual StatusCode getIDOfTypeName(const std::string &typeName, CLID &id) const override
get id associated with type name (if any)
Definition: ClassIDSvc.cxx:138
ClassIDSvc::lock_t
std::lock_guard< mutex_t > lock_t
Definition: ClassIDSvc.h:133
ClassIDSvc::m_DBFiles
Gaudi::Property< std::vector< std::string > > m_DBFiles
Definition: ClassIDSvc.h:117
jobOptions.fileName
fileName
Definition: jobOptions.SuperChic_ALP2.py:39
checker_macros.h
Define macros for attributes used to control the static checker.
PrepareReferenceFile.outfile
outfile
Definition: PrepareReferenceFile.py:42
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: ClassIDSvc.cxx:45
ClassIDSvc.h
a service to manage and verify CLID assignments in athena
Trk::split
@ split
Definition: LayerMaterialProperties.h:38
plotBeamSpotMon.nc
int nc
Definition: plotBeamSpotMon.py:82
ClassIDSvc::getIDOfTypeInfoName
virtual StatusCode getIDOfTypeInfoName(const std::string &typeInfoName, CLID &id) const override
get id associated with type-info name (if any)
Definition: ClassIDSvc.cxx:162
test_athena_ntuple_dumper.paths
paths
Definition: test_athena_ntuple_dumper.py:7
ServiceHandle< IIncidentSvc >