ATLAS Offline Software
ClassIDSvc.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2023 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
61  lock_t lock (m_mutex);
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 {
80  lock_t lock (m_mutex);
81  maybeRescan();
82  return m_clidMap.find(id) != m_clidMap.end();
83 }
84 
85 
86 bool
87 ClassIDSvc::isNameInUse(const std::string& name ) const {
88  lock_t lock (m_mutex);
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 {
98  lock_t lock (m_mutex);
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  const std::string& typeName = m_clidMap.find (clid)->second.first;
205  ATH_MSG_INFO( "CLID: "<< clid << " - type name: " << typeName );
206  }
207  ATH_MSG_INFO( "------------------------------" );
208 }
209 
210 
211 StatusCode
213 {
214  ATH_MSG_VERBOSE( "Initializing " << name() ) ;
215 
217 
218  // set up the incident service:
219  ServiceHandle<IIncidentSvc> pIncSvc ("IncidentSvc", name());
220  CHECK( pIncSvc.retrieve() );
221 
222  pIncSvc->addListener(this, ModuleLoadedIncident::TYPE(), /*priority*/ 100);
223  pIncSvc->release();
224 
225  CHECK( maybeRescan() ); // calls fillDB() if not already done
226 
227  return StatusCode::SUCCESS;
228 }
229 
230 
233  ATH_MSG_INFO( "RE-initializing " << name() ) ;
234  CHECK( fillDB() );
235  return StatusCode::SUCCESS;
236 }
237 
238 
239 StatusCode
241 {
242  if (m_outputFileName != "NULL") {
243  std::ofstream outfile( m_outputFileName );
244  if ( !outfile ) {
245  ATH_MSG_ERROR( "unable to open output CLIDDB file: " << m_outputFileName );
246  return StatusCode::RECOVERABLE;
247  } else {
248  for (CLID clid : sortedIDs()) {
249  const std::string& typeName = m_clidMap[clid].first;
250  const std::string& tiName = m_clidMap[clid].second;
251  outfile << clid << "; " << typeName << "; " << tiName << std::endl;
252  }
253  ATH_MSG_INFO( "finalize: wrote " << m_clidMap.size() <<
254  " entries to output CLIDDB file: " << m_outputFileName );
255  }
256  }
257  return Service::finalize();
258 }
259 
260 
261 void ClassIDSvc::handle(const Incident &inc)
262 {
263  lock_t lock (m_mutex);
264  const ModuleLoadedIncident& modInc(dynamic_cast<const ModuleLoadedIncident&>(inc));
265 
266  getRegistryEntries(modInc.module());
267 }
268 
269 
271 ClassIDSvc::ClassIDSvc(const std::string& name,ISvcLocator* svc)
272  : base_class(name,svc),
273  m_clidDBPath(System::getEnv("DATAPATH"))
274 {
275 }
276 
277 
278 // Return all registered IDs in sorted order.
279 std::vector<CLID> ClassIDSvc::sortedIDs() const
280 {
281  std::vector<CLID> ids;
282  ids.reserve (m_clidMap.size());
283  for (const auto& p : m_clidMap) {
284  ids.push_back (p.first);
285  }
286  std::sort (ids.begin(), ids.end());
287  return ids;
288 }
289 
290 
294  bool allOK(true);
295  for (const std::string& DBFile : m_DBFiles) {
296  DirSearchPath::path clidDB(DBFile);
297 
298  if (clidDB.is_absolute()) {
299  allOK = processCLIDDB(clidDB.string());
300  } else {
301  std::list<DirSearchPath::path> paths(m_clidDBPath.find_all(clidDB));
302  if (paths.empty()) {
303  ATH_MSG_DEBUG( "Could not resolve clid DB path " << clidDB
304  << " using DATAPATH. Skipping it." );
305  } else {
306  for (const auto& p : paths) {
307  allOK &= processCLIDDB(p.string());
308  }
309  }
310  }
311  }
312  return StatusCode(allOK);
313 }
314 
315 
316 bool
318 {
319  std::ifstream ifile(fileName);
320  if (!ifile) {
321  ATH_MSG_WARNING( "processCLIDDB: unable to open " << fileName );
322  return true;
323  }
324 
325  bool allOK(true);
326  unsigned int newEntries(0);
327  std::string line;
328  // Format: CLID;typeName[;typeInfoName]
329  while (allOK && std::getline(ifile, line)) {
330  std::vector<std::string> columns;
331  boost::split(columns, line, boost::is_any_of(";"));
332  long id(-1);
333  if (columns.size()>=2) {
334  boost::trim(columns[0]);
335  try {
336  id = std::stol(columns[0]);
337  } catch (const std::logic_error& e) {
338  ATH_MSG_ERROR( "processCLIDDB: Can't cast ["<< columns[0] << "] to long (clid): " << e.what() );
339  allOK = false;
340  }
341 
342  if (uncheckedSetTypePackageForID(id, columns[1],
343  columns.size()>2 ? columns[2] : "")) {
344  ++newEntries;
345  }
346  }
347  }
348 
349  if (!allOK) {
350  ATH_MSG_ERROR( "processCLIDDB: processing record '" << line
351  << "' from CLIDDB file: " << fileName );
352  } else {
353  ATH_MSG_DEBUG( "processCLIDDB: read " << newEntries <<
354  " entries from CLIDDB file: " << fileName );
355  }
356 
357  return allOK;
358 }
359 
360 
361 bool ClassIDSvc::getRegistryEntries(const std::string& moduleName)
362 {
363  //not only this is fast, but is necessary to prevent recursion
364  if (!CLIDRegistry::hasNewEntries()) return true;
365 
366  bool allOK(true);
367  size_t newEntries(0);
368  //to speed up processing we only take entries added to CLIDRegistry
369  //since last call (thanks Niels!)
370  for (const auto& [clid, typeName, typeInfoName] : CLIDRegistry::newEntries()) {
371  ATH_MSG_VERBOSE( "reading [" << clid << ", " << typeName << ", " << typeInfoName << "]" );
372  if (uncheckedSetTypePackageForID(clid, typeName, typeInfoName)) {
373  ++newEntries;
374  }
375  else {
376  allOK = false;
377  }
378  }
379 
380  if (allOK) {
381  ATH_MSG_INFO( "getRegistryEntries: read " << newEntries
382  << " CLIDRegistry entries for module " << moduleName );
383  } else {
384  ATH_MSG_ERROR("getRegistryEntries: can not read CLIDRegistry entries for module "
385  << moduleName );
386  }
387 
388  return allOK;
389 }
390 
391 
392 StatusCode
394  const std::string& typeName,
395  const std::string& typeInfoName)
396 {
397  // process "raw" typeName
398  std::string procName(typeName);
399  boost::trim(procName);
400 
401  if (procName.empty()) {
402  ATH_MSG_ERROR( "Empty type name for CLID " << id );
403  return StatusCode::FAILURE;
404  }
405 
406  // assign typeInfoName
407  std::string procTiName;
408  if (typeInfoName.empty()) {
409  procTiName = procName;
410  }
411  else {
412  procTiName = typeInfoName;
413  boost::trim(procTiName);
414  }
415 
416  // insert into CLID map
417  const auto& [clid_it, clid_success] = m_clidMap.try_emplace(id, procName, procTiName);
418  if (!clid_success && clid_it->second!=std::make_pair(procName,procTiName)) {
419  ATH_MSG_ERROR( "Cannot set type " << std::make_pair(procName,procTiName) << " for CLID " <<
420  id << ": known type for this ID " << clid_it->second );
421  return StatusCode::FAILURE;
422  }
423 
424  // insert into type name map
425  const auto& [name_it, name_success] = m_nameMap.try_emplace(procName, id);
426  if (!name_success && name_it->second!=id) {
427  ATH_MSG_ERROR( "Cannot set CLID " << id << " for type name '"
428  << procName << "': known CLID for this name " << name_it->second );
429  return StatusCode::FAILURE;
430  }
431 
432  // insert into typeInfo map
433  const auto& [info_it, info_success] = m_tiNameMap.try_emplace(procTiName, id);
434  if (!info_success && info_it->second!=id) {
435  ATH_MSG_ERROR( "Cannot set CLID " << id << " for type-info name '"
436  << procTiName << "' and type '" << procName
437  << "': known CLID for this type-info name " << info_it->second );
438  return StatusCode::FAILURE;
439  }
440 
441  ATH_MSG_VERBOSE( "Set type name '" << procName << "' for CLID " << id <<
442  " with type-info name '" << procTiName << "'" );
443 
444  return StatusCode::SUCCESS;
445 }
446 
447 
449 {
450  // thread-safe because calls are protected by mutex or during initialize
451  ClassIDSvc* nc ATLAS_THREAD_SAFE = const_cast<ClassIDSvc*>(this);
452 
453  // read CLID database in case initialize() was not called yet (ATR-23634)
454  [[maybe_unused]] static bool fillDB ATLAS_THREAD_SAFE = nc->fillDB().isSuccess();
455 
456  // make sure registry is up-to-date
457  bool status = nc->getRegistryEntries ("ALL");
458 
459  return status && fillDB;
460 }
461 
462 
TestSUSYToolsAlg.ifile
ifile
Definition: TestSUSYToolsAlg.py:92
python.tests.PyTestsLib.finalize
def finalize(self)
_info( "content of StoreGate..." ) self.sg.dump()
Definition: PyTestsLib.py:53
checkFileSG.line
line
Definition: checkFileSG.py:75
python.SystemOfUnits.s
int s
Definition: SystemOfUnits.py:131
CLIDRegistry::newEntries
static CLIDVector_t newEntries()
returns an iterator range over the entries added since last time newEntries was called
Definition: CLIDRegistry.cxx:117
python.PerfMonSerializer.p
def p
Definition: PerfMonSerializer.py:743
athena.path
path
python interpreter configuration --------------------------------------—
Definition: athena.py:126
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
trim
std::string trim(const std::string &str, const std::string &whitespace=" \t")
Definition: BTaggingTruthTaggingTool.cxx:1149
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
ClassIDSvc::m_mutex
mutex_t m_mutex
Definition: ClassIDSvc.h:134
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:293
ClassIDSvc::dump
void dump() const
dump to MsgStream contents of in memory DB
Definition: ClassIDSvc.cxx:198
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:261
ClassIDSvc::finalize
virtual StatusCode finalize() override
dump CLIDmap to outputFileName;
Definition: ClassIDSvc.cxx:240
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:45
FortranAlgorithmOptions.fileName
fileName
Definition: FortranAlgorithmOptions.py:13
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:212
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:361
ClassIDSvc::processCLIDDB
bool processCLIDDB(const std::string &fileName)
load clid/names from a "db" file
Definition: ClassIDSvc.cxx:317
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:232
RunExEngineTestITk.DBFile
DBFile
Definition: RunExEngineTestITk.py:49
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:194
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:195
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:271
ClassIDSvc::sortedIDs
std::vector< CLID > sortedIDs() const
Return all registered IDs in sorted order.
Definition: ClassIDSvc.cxx:279
ClassIDSvc::maybeRescan
bool maybeRescan() const
Test to see if anything new has been added to the registry.
Definition: ClassIDSvc.cxx:448
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.
DiTauMassTools::MaxHistStrategyV2::e
e
Definition: PhysicsAnalysis/TauID/DiTauMassTools/DiTauMassTools/HelperFunctions.h:26
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:393
ClassIDSvc::m_outputFileName
Gaudi::Property< std::string > m_outputFileName
Definition: ClassIDSvc.h:121
ReadCalibFromCool.typeName
typeName
Definition: ReadCalibFromCool.py:477
merge.status
status
Definition: merge.py:17
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
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
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:83
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 >