CentralConfig.cc
Go to the documentation of this file.
1 #include <config.h>
2 
3 #include <fwk/CentralConfig.h>
4 #include <fwk/GITGlobalRevision.h>
5 #include <fwk/VModule.h>
6 
7 #include <utl/ReaderErrorReporter.h>
8 #include <utl/ErrorLogger.h>
9 #include <utl/Reader.h>
10 #include <utl/XercesUtil.h>
11 #include <utl/StringCompare.h>
12 
13 #include <fwk/RunController.h>
14 
15 #include "CentralConfig/Md5Fingerprints.icc" // fingerprint generated by configure
16 #include "CentralConfig/Md5Excludes.icc" // list of files to ignore when checking fingerprints
17 
18 #include <xercesc/dom/DOM.hpp>
19 
20 #ifndef _GNU_SOURCE
21 # define _GNU_SOURCE
22 #endif
23 #include <dlfcn.h>
24 #include <boost/filesystem.hpp>
25 #include <boost/process.hpp>
26 
27 #include <fstream>
28 
29 using namespace fwk;
30 using namespace std;
31 using namespace utl;
32 using namespace xercesc;
33 namespace bfs = boost::filesystem;
34 
35 
36 namespace fwk {
37 
39  bool CentralConfig::fgIsInitialized = false;
40  bool CentralConfig::fgValidate = true;
41 
42 
43  string
44  AsString(DOMNode& n)
45  {
46  switch (n.getNodeType()) {
47  case DOMNode::TEXT_NODE:
48  return utl::AsString(n.getNodeValue());
49  case DOMNode::COMMENT_NODE:
50  return "<!--" + utl::AsString(n.getNodeValue()) + "-->";
51  default:
52  return "!!!unhandled DOMNode type " + to_string(n.getNodeType()) + "!!!";
53  }
54  }
55 
56 
57  inline
58  string
59  AsXML(const AttributeMap& attr)
60  {
61  ostringstream os;
62  for (const auto& kv : attr)
63  os << ' ' << kv.first << "=\"" << kv.second << '\"';
64  return os.str();
65  }
66 
67 
68  const char*
70  {
71  Dl_info dlInfo;
72  return dladdr((void*)GetLibraryPath, &dlInfo) ? dlInfo.dli_fname : "";
73  }
74 
75 }
76 
77 
79 {
80  const char* const libPath = GetLibraryPath();
81  if (libPath && libPath[0])
82  fInstallPath = bfs::path(libPath).parent_path().parent_path().string();
83 }
84 
85 
87 {
88  delete fBootstrapReader;
89 
90  for (const auto& c : fConfigMap)
91  delete c.second.GetReader();
92 
93  fgIsInitialized = false;
94 }
95 
96 
110 CentralConfig::GetInstance(const string& name,
111  const bool fingerprintFatal,
112  const bool validate)
113 {
114  fgValidate = validate;
115 
116  static CentralConfig cc; // Mayer's singleton
117 
118  fgInstance = &cc;
119 
120  static string bootstrapFile;
121 
122  if (!fgIsInitialized) {
123 
124  cc.ReadConfig(name);
125  cc.FillMd5Excludes();
126  cc.CheckFingerprints(fingerprintFatal);
127  fgIsInitialized = true;
128  bootstrapFile = name;
129 
130  } else if (bootstrapFile != name) {
131 
132  INFO("You have requested the instance of CentralConfig "
133  "specifying a bootstrap file. "
134  "However, in a previous instantiation, you requested "
135  "a different bootstrap file. This is not "
136  "allowed. Not changing the configuraton.");
137 
138  }
139 
140  return fgInstance;
141 }
142 
143 
144 void
145 CentralConfig::Reset(const std::string& bootstrapFileName,
146  const bool fingerprintFatal,
147  const bool validate)
148 {
149  const string b = fgInstance->GetBootstrapUri();
150  fgInstance = nullptr;
151  fgIsInitialized = false;
152  if (bootstrapFileName.empty())
153  CentralConfig::GetInstance(b, fingerprintFatal, validate);
154  else
155  CentralConfig::GetInstance(bootstrapFileName, fingerprintFatal, validate);
156 }
157 
158 
159 void
160 CentralConfig::ReadConfig(const string& bootstrapFile)
161 {
162  if (fBootstrapReader)
163  throw XMLParseException("CentralConfig should be initialized only once!");
164 
165  fBootstrapReader = new Reader(bootstrapFile, Reader::eSCHEMA);
166 
167  Branch topBranch = fBootstrapReader->GetTopBranch();
168 
169  Branch severityBranch = topBranch.GetChild("minSeverity");
170  if (severityBranch) {
171  ErrorLogger& logger = ErrorLogger::GetInstance();
172  string severity;
173  severityBranch.GetData(severity);
174  if (severity == "debug")
175  logger.SetMinSeverity(ErrorLogger::eDebug);
176  else if (severity == "info")
177  logger.SetMinSeverity(ErrorLogger::eInfo);
178  else if (severity == "warning")
179  logger.SetMinSeverity(ErrorLogger::eWarning);
180  else if (severity == "error")
181  logger.SetMinSeverity(ErrorLogger::eError);
182  else if (severity == "fatal")
183  logger.SetMinSeverity(ErrorLogger::eFatal);
184  }
185 
186  // Loop over all children of the top Branch which are called
187  // centralConfig. configLinks appearing in later centralConfig
188  // file will replace those in earlier ones
189  //
190  for (Branch ccB = topBranch.GetFirstChild(); ccB; ccB = ccB.GetNextSibling()) {
191  const string& name = ccB.GetName();
192  if (name == "centralConfig" || name == "defaultConfig")
193  FillMap(ccB);
194  else if (name == "parameterOverrides")
195  ReplaceParameters(ccB);
196  }
197 }
198 
199 
213 {
214  if (!fgInstance)
216  "The first time you call CentralConfig::GetInstance(...), "
217  "you MUST pass the name of the bootstrap configuration file"
218  );
219 
220  return fgInstance;
221 }
222 
223 
228 Branch
229 CentralConfig::GetTopBranch(const std::string& id)
230 {
231  const Reader* const reader = GetReader(id);
232  if (reader)
233  return reader->GetTopBranch();
234  else {
235  ostringstream msg;
236  msg << "Cannot find Configuration file for <configLink> with id=\""
237  << id << '"';
238  Branch b;
239  b.SetWarning(msg.str());
240  return b;
241  }
242 }
243 
244 
245 const Reader*
246 CentralConfig::GetReader(const string& id)
247 {
248  fUsedConfigs.emplace(id);
249 
250  const auto it = fConfigMap.find(id);
251 
252  if (it != fConfigMap.end()) {
253 
254  Reader* const reader = it->second.GetReader();
255  if (reader)
256  return reader;
257  else {
258  ostringstream msg;
259  msg << "You requested a Reader for a file format "
260  "which cannot be accessed by the Reader "
261  "Configuration Id '"
262  << it->second.fXLink << "' of type "
263  << it->second.fFileType;
264  INFO(msg);
265  }
266 
267  } else {
268  ostringstream msg;
269  msg << "Cannot find requested Id: '" << id << '\'';
270  DEBUGLOG(msg);
271  }
272 
273  return nullptr;
274 }
275 
276 
277 string
279 {
280  if (fBootstrapReader)
281  return fBootstrapReader->GetUri();
282  return "";
283 }
284 
285 
286 /*void
287 CentralConfig::SetTopBranch(const std::string& id, const utl::Branch& branch)
288 {
289  ConfigLink configLink;
290  configLink.fFileType = "XML";
291  configLink.fReader = new Reader(branch.Clone());
292 
293  // Check for configLink override
294  const auto previousConfigLink = fConfigMap.find(id);
295  if (previousConfigLink != fConfigMap.end()) {
296  delete previousConfigLink->second.fReader;
297  previousConfigLink->second = configLink;
298  } else {
299  fConfigMap.insert(pair<string, ConfigLink>(id, configLink));
300  GetTopBranch(id);
301  }
302 }*/
303 
304 
305 void
306 CentralConfig::FillMap(const Branch& configBranch)
307 {
308  typedef map<string, list<string>> OvConfig;
309 
310  if (!configBranch)
311  return;
312 
313  // holds information about overridden config files for report generation
314  OvConfig overriddenConfigs;
315 
316  for (Branch cB = configBranch.GetFirstChild(); cB; cB = cB.GetNextSibling()) {
317 
318  if (cB.GetName() == "configLink") {
319 
320  const AttributeMap attMap = cB.GetAttributes();
321 
322  string id;
323  {
324  const auto it = attMap.find("id");
325  if (it != attMap.end())
326  id = it->second;
327  else {
328  const auto it = attMap.find("ID");
329  if (it != attMap.end())
330  id = it->second;
331  else
332  AbortParse("<configLink> found without 'id' attribute.");
333  }
334  }
335 
336  ConfigLink configLink;
337  {
338  const auto it = attMap.find("type");
339  if (it == attMap.end())
340  AbortParse("<configLink> found without 'type' attribute.");
341  configLink.fFileType = it->second;
342  }
343  {
344  const auto it = attMap.find("xlink:href");
345  if (it == attMap.end())
346  AbortParse("<configLink> found without 'xlink:href' attribute.");
347  configLink.fXLink = it->second;
348  }
349 
350  // Set the reader
351  if (StringEquivalent(configLink.fFileType, "XML")) {
352 
353  if (configLink.fXLink[0] == '#') {
354 
355  const string path = configLink.fXLink.substr(1);
356 
357  Branch branch = Find(path);
358  if (branch) {
359  branch = branch.GetFirstChild();
360  const string mybranch = AsString(branch);
361  try {
362  configLink.fReader = new Reader(ReaderStringInput(mybranch));
363  } catch (XMLParseException& ex) {
364  AbortParse("Failure to parse from input string. " + ex.GetMessage());
365  }
366  }
367  } else if (!fgValidate) {
368  try {
369  ostringstream msg;
370  msg << "Explicit request to parse a file without validation."
371  "Filename = " << configLink.fXLink;
372  WARNING(msg);
373  configLink.fReader = new Reader(configLink.fXLink, Reader::eNONE);
374  } catch (XMLParseException& ex) {
375  AbortParse("Failure to parse with (validation switched off). " + ex.GetMessage());
376  }
377  } else {
378  try {
379  configLink.fReader = new Reader(configLink.fXLink, Reader::eSCHEMA);
380  } catch (XMLParseException& ex) {
381  AbortParse(ex.GetMessage());
382  }
383  }
384  }
385 
386  // Check for configLink override
387  const auto previousConfigLink = fConfigMap.find(id);
388 
389  if (previousConfigLink != fConfigMap.end()) {
390 
391  if (previousConfigLink->second.fXLink != configLink.fXLink) {
392  // previously overridden
393  auto& ov = overriddenConfigs[id];
394  if (ov.empty())
395  ov.push_back(previousConfigLink->second.fXLink);
396  ov.push_back(configLink.fXLink);
397  }
398 
399  delete previousConfigLink->second.fReader;
400  fConfigMap.erase(previousConfigLink);
401 
402  }
403 
404  // Insert the config info into the configMap
405  fConfigMap.emplace(id, configLink);
406 
407  }
408 
409  }
410 
411  // generate report about overridden configuration files
412  if (!overriddenConfigs.empty()) {
413  ostringstream msg;
414  msg << "The following configuration files have been overridden. "
415  "Files sorted from original to newest override:";
416  for (const auto& c : overriddenConfigs) {
417  const string& id = c.first;
418  const list<string>& files = c.second;
419  if (files.empty())
420  continue;
421  msg << "\n * Id: '" << id << "', files:";
422  const unsigned int n = files.size();
423  unsigned int i = 0;
424  for (const auto& f : files) {
425  msg << "\n ";
426  if (!i)
427  msg << "(original )";
428  else if (i == n-1)
429  msg << "(replaced by)";
430  else
431  msg << "( old)";
432  msg << " '" << f << '\'';
433  ++i;
434  }
435  }
436  INFO(msg);
437  }
438 
439  static bool checkedAlready = false;
440  if (!checkedAlready) {
441  checkedAlready = true;
442  // check for duplicated top branches
443  map<string, set<string>> dupBrCl;
444  for (auto it = fConfigMap.begin(), end = fConfigMap.end(); it != end; ++it) {
445  if (const Reader* const ri = it->second.GetReader()) {
446  const string& topBranchName = ri->GetTopBranch().GetName();
447  for (auto jt = next(it); jt != end; ++jt) {
448  if (const Reader* const rj = jt->second.GetReader()) {
449  if (topBranchName == rj->GetTopBranch().GetName()) {
450  auto& d = dupBrCl[topBranchName];
451  d.insert(it->first);
452  d.insert(jt->first);
453  }
454  }
455  }
456  }
457  }
458  if (!dupBrCl.empty()) {
459  ostringstream warn;
460  for (const auto& d : dupBrCl) {
461  warn << "The same top branch <" << d.first << "> has been "
462  "encountered in the following <configLink>s with ids:";
463  for (const auto& c : d.second)
464  warn << ' ' << c;
465  }
466  WARNING(warn);
467  }
468  }
469 }
470 
471 
478 void
480 {
481  for (Branch cB = b.GetFirstChild(); cB; cB = cB.GetNextSibling()) {
482 
483  // Look up the reader for requested configLink override
484  // and override specified data
485  const auto atts = cB.GetAttributes();
486  const auto idIt = atts.find("id");
487  if (idIt != atts.end()) {
488  const auto configIt = fConfigMap.find(idIt->second);
489  if (configIt != fConfigMap.end()) {
490  const ConfigLink& readerLink = configIt->second;
491 
492  // guaranteed to exist by validation
493  Branch originalBranch = readerLink.GetReader()->GetTopBranch();
494  Branch replacementBranch = cB.GetFirstChild();
495  if (replacementBranch)
496  DescendAndReplace(replacementBranch, originalBranch);
497  else {
498  ostringstream msg;
499  msg << "The <configLink> with attributes " << AsXML(cB.GetAttributes())
500  << " has no children. No configuration data will be replaced for that <configLink>.";
501  ERROR(msg);
502  throw XMLParseException(msg.str());
503  }
504 
505  // Revalidate the modified document
506  ReaderStringInput readerFromStringInput(readerLink.GetReader()->GetTopBranch().String());
507  Reader validationReader(readerFromStringInput, Reader::eSCHEMA);
508 
509  } else {
510  ostringstream msg;
511  msg << "The <parameterOverrides> portion of the bootstrap file specifies "
512  "a <configLink> with " << AsXML(cB.GetAttributes()) << ", "
513  "but no matching <configLink> is found in the bootstrap file.";
514  ERROR(msg);
515  throw XMLParseException(msg.str());
516  }
517  }
518  }
519 }
520 
521 
533 void
535  Branch& originalBranch)
536 {
537  while (replacementBranch) {
538 
539  const string replacementBranchName = replacementBranch.GetName();
540  const string originalBranchName = originalBranch.GetName();
541  AttributeMap replacementBranchAtts = replacementBranch.GetAttributes();
542  const AttributeMap originalBranchAtts = originalBranch.GetAttributes();
543 
544  // skip units in branch selection
545  // (units are a special attribute which are not selected upon)
546  replacementBranchAtts.erase("unit");
547  replacementBranchAtts.erase("UNIT");
548 
549  if (originalBranch.GetParent() && // skip the document node.
550  (replacementBranchName != originalBranchName ||
551  replacementBranchAtts != originalBranchAtts)) {
552  originalBranch = originalBranch.GetSibling(replacementBranchName, replacementBranchAtts);
553  }
554 
555  if (!originalBranch) {
556  ostringstream msg;
557  msg << "Failure while attempting to override configuration parameters. "
558  "An override was requested for a branch "
559  "<" << replacementBranchName << AsXML(replacementBranchAtts) << "> "
560  "but a branch "
561  "<" << originalBranchName << AsXML(originalBranchAtts) << "> "
562  "was found instead at this place in the original configuration file.";
563  ERROR(msg);
564  throw XMLParseException(msg.str());
565  }
566 
567  string replacementData;
568  replacementBranch.GetData(replacementData);
569 
570  // unsupported case mentioned above
571  if (replacementBranch.GetFirstChild() && !replacementData.empty()) {
572  ostringstream msg;
573  msg << "Problem encountered while trying to replace branch "
574  "<" << originalBranchName << AsXML(originalBranchAtts) << "> "
575  "with branch "
576  "<" << replacementBranchName << AsXML(replacementBranchAtts) << ">. "
577  "Note that replacing a branch, which contains both data and "
578  "sub-branches, is not supported.";
579  WARNING(msg);
580  throw XMLParseException(msg.str());
581  }
582 
583  if (!replacementData.empty()) {
584 
585  if (replacementBranch.GetFirstChild()) {
586  ostringstream msg;
587  msg << "Problem encountered while trying to replace branch "
588  "<" << originalBranchName << AsXML(originalBranchAtts) << "> "
589  "with branch "
590  "<" << replacementBranchName << AsXML(replacementBranchAtts) << ">. "
591  "Cannot replace a branch which contains both data and sub-branches.";
592  WARNING(msg);
593  throw XMLParseException(msg.str());
594  }
595 
596  const auto dom = originalBranch.GetDOMNode();
597 
598  if (dom->getChildNodes()->getLength() != 1) {
599  ostringstream msg;
600  msg << "The data in the original branch "
601  "<" << originalBranchName << AsXML(originalBranchAtts) << "> "
602  "is unexpectedly split-up into several strings (probably by a comment) and thus "
603  "cannot be simply replaced with the string of the replacement branch "
604  "<" << replacementBranchName << AsXML(replacementBranchAtts) << ">. "
605  "Please remove any comments in the data string of the original branch.\n"
606  "original branch = ";
607  auto c = dom->getFirstChild();
608  if (!c)
609  msg << "\"\"";
610  else {
611  msg << '"' << fwk::AsString(*c) << '"';
612  for ( ; c; c = c->getNextSibling())
613  msg << " + \"" << fwk::AsString(*c) << '"';
614  }
615  msg << "\nreplacement branch = \"" << replacementBranch.Get<string>() << '"';
616  ERROR(msg);
617  throw XMLParseException(msg.str());
618  }
619 
620  const auto doc = dom->getOwnerDocument();
621  // replace text in the node
622  const auto replacementText =
623  doc->createTextNode(XercesPtrX(XMLString::transcode(replacementData.c_str())).Get());
624  // actual branch replacement starts here
625  dom->replaceChild(replacementText, dom->getFirstChild())->release();
626 
627  // replace the unit attribute of the node, if there is one
628  DOMAttr* replacementUnitAtt = nullptr;
629  DOMElement* const replacementElement = dynamic_cast<DOMElement*>(replacementBranch.GetDOMNode());
630  const XMLCh* replacementUnit = nullptr;
631 
632  if (replacementElement) {
633  const XercesPtrX attrName(XMLString::transcode("unit"));
634  replacementUnitAtt = replacementElement->getAttributeNode(attrName.Get());
635  if (!replacementUnitAtt) {
636  const XercesPtrX attrName(XMLString::transcode("UNIT"));
637  replacementUnitAtt = replacementElement->getAttributeNode(attrName.Get());
638  }
639  }
640  if (replacementUnitAtt)
641  replacementUnit = replacementUnitAtt->getValue();
642 
643  DOMAttr* originalUnitAtt = nullptr;
644  DOMElement* const originalElement = dynamic_cast<DOMElement*>(originalBranch.GetDOMNode());
645 
646  if (originalElement) {
647  const XercesPtrX attrName(XMLString::transcode("unit"));
648  originalUnitAtt = originalElement->getAttributeNode(attrName.Get());
649  if (!originalUnitAtt) {
650  const XercesPtrX attrName(XMLString::transcode("UNIT"));
651  originalUnitAtt = originalElement->getAttributeNode(attrName.Get());
652  }
653  }
654  if (originalUnitAtt && replacementUnitAtt)
655  originalUnitAtt->setValue(replacementUnit);
656  // Replacement ends here
657  }
658 
659  // descend to next level in the hierarchy
660  Branch replacementChild = replacementBranch.GetFirstChild();
661  Branch originalChild = originalBranch.GetFirstChild();
662  if (replacementChild && originalChild)
663  DescendAndReplace(replacementChild, originalChild);
664 
665  replacementBranch = replacementBranch.GetNextSibling();
666  } // while
667 }
668 
669 
670 void
671 CentralConfig::CheckFingerprints(const bool fingerprintFatal)
672 {
673  // Fill the Fingerprint map generated at config time, if necessary
674  if (!fConfigTimeFingerMap.size())
675  FillConfigTimeFingerMap();
676 
677  list<string> multipleMD5List;
678 
679  for (const auto& runConfig : fConfigMap) {
680 
681  if (fMd5Excludes.find(runConfig.first) != fMd5Excludes.end())
682  continue;
683 
684  const string& linkName = runConfig.second.GetLink();
685 
686  // Don't attempt to compute the md5 if the config link is an Xpath.
687  // In such a case, the config file has been concatenated into a log
688  // which will have already been checked at the time said log
689  // was generated.
690  if (linkName.empty() || linkName[0] == '#')
691  continue;
692 
693  const auto cmd = "openssl dgst -md5 " + linkName;
694 
695  namespace bp = boost::process;
696  bp::ipstream is;
697  bp::child pipe(cmd, bp::std_out > is);
698  typedef std::istreambuf_iterator<char> IstrIt;
699  const std::string fullOut{IstrIt{is}, IstrIt{}};
700  pipe.wait();
701  if (pipe.exit_code())
702  WARNING(str(boost::format("checksum command `%1%` returned status %2%") % cmd % pipe.exit_code()));
703 
704  if (fullOut.empty()) {
705  WARNING("received no output from '" + cmd + "'");
706  continue;
707  }
708 
709  string runFinger = fullOut.substr(fullOut.find("=") + 1);
710  boost::trim(runFinger);
711 
712  // Find the fingerprint for this run-time config file in the fingerprint map
713  // generated at configuration time. Paths are currently
714  // stripped off both the run-time config file name and the
715  // filename read at configure time.
716 
717  const auto start = linkName.rfind("/") + 1;
718  const auto length = linkName.rfind(".xml") - start;
719  const string strippedName = linkName.substr(start, length);
720 
721  const auto fileMatch = fConfigTimeFingerMap.equal_range(strippedName);
722  int nFilenameMatches = 0;
723  bool fingerprintMatch = false;
724  for (auto fingerIt = fileMatch.first; fingerIt != fileMatch.second; ++fingerIt) {
725  ++nFilenameMatches;
726  if (fingerIt->second == runFinger)
727  fingerprintMatch = true;
728  }
729 
730  if (!nFilenameMatches)
731  fNoMd5List.push_back(strippedName);
732  else if (nFilenameMatches > 1)
733  multipleMD5List.push_back(strippedName);
734  else if (!fingerprintMatch)
735  fMismatchedMd5List.push_back(strippedName);
736 
737  }
738 
739  // Warn about missing MD5s
740  if (!fNoMd5List.empty()) {
741  ostringstream msg;
742  msg << "No configuration-time MD5 fingerprint found for the following configuration files. "
743  << "Checking the validity of these configuration files is impossible.";
744  for (const auto& file : fNoMd5List)
745  msg << "\n - " << file;
746  WARNING(msg);
747  }
748 
749  // Warn about multiple MD5s
750  if (!multipleMD5List.empty()) {
751  ostringstream msg;
752  msg << "More than one configuration-time md5 fingerprint found corresponding to each of the "
753  << "following configuration files. If at least one matching fingerprint is found, I "
754  << "will continue execution. But you have been warned.";
755  for (const auto& file : multipleMD5List)
756  msg << "\n - " << file;
757  WARNING(msg);
758  }
759 
760  // Bitterly complain about mismatching MD5s
761  if (!fMismatchedMd5List.empty()) {
762  ostringstream msg;
763  msg << "Incorrect MD5 fingerprints were found for the following configuration files. "
764  << "This implies this configuration file has been altered.";
765  for (const auto& file : fMismatchedMd5List)
766  msg << "\n - " << file;
767  if (fingerprintFatal) {
768  ERROR(msg);
769  throw InvalidConfigurationException(msg.str());
770  } else
771  WARNING(msg);
772  }
773 }
774 
775 
776 void
777 CentralConfig::WriteConfig(const string& fileName)
778 {
779  ofstream out(fileName.c_str());
780  out << GetConfig();
781 }
782 
783 
784 string
786 {
787  // poor-man's lazy evaluation, to avoid adding to the config
788  // stream if GetConfig is called multiple times
789  // This should probably be replaced with something better.
790  if (fConfigInfoIsValid)
791  return fConfigInfo.str();
792  fConfigInfoIsValid = true;
793 
794  // stylesheet to browse
795  // (removing stylesheet because it is unmaintained.. tp 2 July 07)
796  // fConfigInfo << "<?xml-stylesheet href=\""
797  // << LOGSTYLESHEETDIR << "/LogStyleSheet.xsl\" type=\"text/xsl\"?>\n\n"
798 
799  fConfigInfo << "<?xml version='1.0' encoding='iso-8859-1'?>\n"
800  "<bootstrap xmlns:xlink=\"http://www.auger.org/schema/types\">\n"
801  "<header>\n"
802  "<softwareVersion> " << OFFLINE_PACKAGE_STRING << " </softwareVersion>\n"
803  "<GITGlobalRevision> " << GITGlobalRevision::GetInstance().GetId() << " </GITGlobalRevision>\n";
804 
805  if (fNoMd5List.size()) {
806  fConfigInfo << "<noMd5> <!-- no md5 fingerprint was found for these config files -->\n";
807  for (const auto& file : fNoMd5List)
808  fConfigInfo << " " << file << '\n';
809  fConfigInfo << "</noMd5>\n";
810  }
811  if (fMismatchedMd5List.size()) {
812  fConfigInfo << "<mismatchedMd5> "
813  "<!-- the md5 fingerprints for these config files do not match the defaults -->\n";
814  for (const auto& file : fMismatchedMd5List)
815  fConfigInfo << " " << file << '\n';
816  fConfigInfo << "</mismatchedMd5>\n";
817  }
818 
819  fConfigInfo << "<moduleVersions>\n";
820 
821  const auto& usedModules = RunController::GetInstance().GetUsedModuleNames();
822  for (const auto& name : usedModules) {
823  VModule& mod = RunController::GetInstance().GetModule(name);
824  fConfigInfo
825  << " <module>\n"
826  " <logicalName> " << name << " </logicalName>\n"
827  " <lastSVNRevision> " << mod.GetVersionInfo(VModule::eRevisionNumber) << " </lastSVNRevision>\n"
828  " <lastRevisionDate> " << mod.GetVersionInfo(VModule::eDate) << " </lastRevisionDate>\n"
829  " <lastEditor> " << mod.GetVersionInfo(VModule::eLastEditor) << " </lastEditor>\n"
830  " </module>\n";
831  }
832 
833  fConfigInfo << "</moduleVersions>\n"
834  "</header>\n"
835  "<centralConfig>\n";
836  LogBootstrap();
837  fConfigInfo << "</centralConfig>\n";
838 
839  for (const auto& conf : fUsedConfigs) {
840 
841  const auto used = fConfigMap.find(conf);
842  if (used != fConfigMap.end()) {
843 
844  // Here we fiddle the document tag such that no namespace or schema
845  // stuff appears in it. This is necessary, since otherwise the
846  // readback gets confused and throws exceptions. It appears that
847  // namespace/schema related attributes can only be in the very top
848  // document tag.
849  Branch topB = used->second.GetReader()->GetTopBranch();
850  fConfigInfo << '<' << conf << ">\n"
851  " <" << topB.GetName() << ">\n"; // drops any attributes
852 
853  for (auto b = topB.GetFirstChild(); b; b = b.GetNextSibling())
854  fConfigInfo << AsString(b, 4);
855 
856  fConfigInfo << " </" << topB.GetName() << ">\n"
857  "</" << conf << ">\n";
858 
859  }
860 
861  }
862 
863  fConfigInfo << "</bootstrap>\n";
864 
865  return fConfigInfo.str();
866 }
867 
868 
869 // called from GetConfig
870 
871 void
873 {
874  for (auto ccB = fBootstrapReader->GetTopBranch().GetFirstChild(); ccB; ccB = ccB.GetNextSibling()) {
875  if (ccB.GetName() == "centralConfig" || ccB.GetName() == "defaultConfig") {
876  ostringstream attributes;
877  for (auto cLink = ccB.GetFirstChild(); cLink; cLink = cLink.GetNextSibling()) {
878  const auto attr = cLink.GetAttributes();
879  const string& id = attr.find("id")->second;
880  for (const auto& a : attr) {
881  attributes << ' ' << a.first << "=\"";
882  if (a.first == "xlink:href")
883  attributes << '#' << id;
884  else
885  attributes << a.second;
886  attributes << '"';
887  }
888  for (const auto& c : fUsedConfigs) {
889  if (id == c) {
890  fConfigInfo << " <" << cLink.GetName() << attributes.str() << "/>\n";
891  break;
892  }
893  }
894  attributes.str("");
895  }
896  }
897  }
898 }
899 
900 
901 Branch
902 CentralConfig::Find(std::string path)
903 {
904  string name;
905  Branch branch = fBootstrapReader->GetTopBranch();
906  while (path.find("/") != string::npos) {
907  name = path.substr(0, path.find("/"));
908  path = path.substr(path.find("/") + 1);
909  branch = branch.GetChild(name);
910  }
911  branch = branch.GetChild(path);
912  return branch;
913 }
914 
915 
916 string
917 CentralConfig::AsString(const Branch& branch, const int indent, const int indentIncrement)
918 {
919  stringstream contents;
920 
921  contents << string(indent, ' ') << '<' << branch.GetName();
922 
923  stringstream attrString;
924  for (const auto& a : branch.GetAttributes())
925  attrString << ' ' << a.first << "=\"" << a.second << '\"';
926  contents << attrString.str() << '>';
927 
928  Branch child = branch.GetFirstChild();
929  if (!child) {
930  // one-liner
931  contents << ' ' << branch.Get<string>() << ' ' << "</" << branch.GetName() << ">\n";
932  } else {
933  // recurse
934  contents << '\n';
935  do {
936  contents << AsString(child, indent + indentIncrement, indentIncrement);
937  child = child.GetNextSibling();
938  } while (child);
939  contents << string(indent, ' ') << "</" << branch.GetName() << ">\n";
940  }
941 
942  return contents.str();
943 }
944 
945 
948 {
949  return CentralConfig::IdIterator(fConfigMap.begin());
950 }
951 
952 
955 {
956  return CentralConfig::IdIterator(fConfigMap.end());
957 }
958 
959 
960 void
962 {
963  ostringstream msg;
964  msg << "Aborting configuration because of parse error. " << s;
965  ERROR(msg);
966  throw XMLParseException(msg.str());
967 }
Branch GetTopBranch() const
Definition: Branch.cc:63
void SetWarning(const std::string &wrn)
Definition: Branch.h:279
IdIterator IdsEnd()
Id&#39;s end.
static bool fgIsInitialized
Branch GetParent() const
Definition: Branch.cc:79
void DescendAndReplace(utl::Branch replacement, utl::Branch &original)
Class to handle routing and writing of error messages.
Definition: ErrorLogger.h:34
void CheckFingerprints(const bool fingerprintFatal)
std::string AsString(const XMLCh *const xStr)
Definition: XercesUtil.h:77
void SetMinSeverity(const ESeverityLevel severity)
Set minimal severity for reporting.
Definition: ErrorLogger.h:95
std::string String() const
Dump the branch into a string.
Definition: Branch.cc:593
Base class for exceptions arising because configuration data are not valid.
boost::transform_iterator< InternalIdFunctor, InternalConfigIterator, std::string > IdIterator
IdIterator returns a pointer to a config link Id.
Definition: CentralConfig.h:93
xercesc::DOMNode * GetDOMNode() const
Definition: Branch.h:293
bool is(const double a, const double b)
Definition: testlib.cc:113
std::map< std::string, std::string > AttributeMap
Definition: Branch.h:24
std::string GetConfig()
Get configuration in a string.
string AsString(DOMNode &n)
void FillMap(const utl::Branch &branch)
#define INFO(message)
Macro for logging informational messages.
Definition: ErrorLogger.h:161
static void Reset(const std::string &bootstrapFileName, const bool fingerprintFatal=false, const bool validate=true)
vector< t2list > out
output of the algorithm: a list of clusters
Definition: XbAlgo.cc:32
Branch GetChild(const std::string &childName) const
Get child of this Branch by child name.
Definition: Branch.cc:211
std::string GetVersionInfo(const VersionInfoType v) const
Retrieve different sorts of module version info.
Definition: VModule.cc:26
Exception for errors encountered when parsing XML.
bool StringEquivalent(const std::string &a, const std::string &b, Predicate p)
Utility to compare strings for equivalence. It takes a predicate to determine the equivalence of indi...
Definition: StringCompare.h:38
static CentralConfig * fgInstance
utl::Branch Find(std::string path)
Branch GetTopBranch() const
Get the top Branch (represents same entity as document node)
Definition: Reader.h:45
Base class to report exceptions in IO.
const char * GetLibraryPath()
T Get() const
Definition: Branch.h:271
AttributeMap GetAttributes() const
Get a map&lt;string, string&gt; containing all the attributes of this Branch.
Definition: Branch.cc:267
Branch GetNextSibling() const
Get next sibling of this branch.
Definition: Branch.cc:284
Utility for parsing XML files.
Definition: Reader.h:25
Iterator next(Iterator it)
Class representing a document branch.
Definition: Branch.h:107
void AbortParse(const std::string &s="")
constexpr double s
Definition: AugerUnits.h:163
This just defines a type which holds some character data to be parsed by the Reader.
Definition: Reader.h:88
#define DEBUGLOG(message)
Macro for logging debugging messages.
Definition: ErrorLogger.h:157
void ReplaceParameters(const utl::Branch &)
void ReadConfig(const std::string &bootstrapFile)
#define WARNING(message)
Macro for logging warning messages.
Definition: ErrorLogger.h:163
void GetData(bool &b) const
Overloads of the GetData member template function.
Definition: Branch.cc:644
std::string GetName() const
function to get the Branch name
Definition: Branch.cc:374
Module interface.
Definition: VModule.h:53
const string file
string AsXML(const AttributeMap &attr)
static bool fgValidate
std::string AsString(const utl::Branch &branch, const int indent=0, const int indentIncrement=2)
const utl::Reader * GetReader(const std::string &id)
Get the Reader for moduleConfigLink with given id (XML files)
std::string GetBootstrapUri()
static CentralConfig * GetInstance()
Use this the first time you get an instance of central configuration.
XercesPtr< XMLCh > XercesPtrX
Definition: XercesUtil.h:69
Main configuration utility.
Definition: CentralConfig.h:51
Branch GetFirstChild() const
Get first child of this Branch.
Definition: Branch.cc:98
void WriteConfig(const std::string &fileName="")
Get the link name for moduleConfigLink with given id (any)
Branch GetSibling(const std::string &childName) const
Get sibling by name.
Definition: Branch.cc:347
double mod(const double d, const double periode)
#define ERROR(message)
Macro for logging error messages.
Definition: ErrorLogger.h:165
IdIterator IdsBegin()
Id&#39;s begin.
const std::string & GetMessage() const
Retrieve the message from the exception.
utl::Branch GetTopBranch(const std::string &id)
Get top branch for moduleConfigLink with given id (XML files)
std::string GetConfig()
Definition: fwkPython.cc:23

, generated on Tue Sep 26 2023.