otsdaq  v1_01_02
 All Classes Namespaces Functions
ConfigurationBase.cc
1 #include "otsdaq-core/ConfigurationDataFormats/ConfigurationBase.h"
2 #include "otsdaq-core/ConfigurationDataFormats/ConfigurationInfoReader.h"
3 
4 #include <iostream> // std::cout
5 #include <typeinfo>
6 
7 
8 using namespace ots;
9 
10 
11 #undef __MF_SUBJECT__
12 #define __MF_SUBJECT__ "ConfigurationBase"
13 #undef __MF_HDR__
14 #define __MF_HDR__ __COUT_HDR_FL__ << getConfigurationName() << ": "
15 
16 
17 //==============================================================================
18 //ConfigurationBase
19 // If a valid string pointer is passed in accumulatedExceptions
20 // then allowIllegalColumns is set for InfoReader
21 // If accumulatedExceptions pointer = 0, then illegal columns throw std::runtime_error exception
22 ConfigurationBase::ConfigurationBase(std::string configurationName,
23  std::string *accumulatedExceptions)
24 : MAX_VIEWS_IN_CACHE (5)//This is done, so that inheriting configuration classes could have varying amounts of cache
25 , configurationName_ (configurationName)
26 , activeConfigurationView_(0)
27 {
28  //info reader fills up the mockup view
29  ConfigurationInfoReader configurationInfoReader(accumulatedExceptions);
30  try //to read info
31  {
32  std::string returnedExceptions = configurationInfoReader.read(this);
33 
34  if(returnedExceptions != "")
35  __MOUT_ERR__ << returnedExceptions << std::endl;
36 
37  if(accumulatedExceptions) *accumulatedExceptions += std::string("\n") + returnedExceptions;
38  }
39  catch(...) //if accumulating exceptions, continue to and return, else throw
40  {
41  __SS__ << "Failure in configurationInfoReader.read(this)" << std::endl;
42  __MOUT_ERR__ << "\n" << ss.str();
43  if(accumulatedExceptions) *accumulatedExceptions += std::string("\n") +
44  ss.str();
45  else throw;
46  return; //do not proceed with mockup check if this failed
47  }
48 
49  //call init on mockup view to verify columns
50  try
51  {
52  getMockupViewP()->init();
53  }
54  catch(std::runtime_error& e) //if accumulating exceptions, continue to and return, else throw
55  {
56  if(accumulatedExceptions) *accumulatedExceptions += std::string("\n") + e.what();
57  else throw;
58  }
59 }
60 //==============================================================================
61 //ConfigurationBase
62 // Default constructor is only used to create special tables
63 // not based on an ...Info.xml file
64 // e.g. the ConfigurationGroupMetadata table in ConfigurationManager
65 ConfigurationBase::ConfigurationBase(void)
66 : MAX_VIEWS_IN_CACHE (1)//This is done, so that inheriting configuration classes could have varying amounts of cache
67 , configurationName_ ("")
68 , activeConfigurationView_(0)
69 {
70 }
71 
72 //==============================================================================
73 ConfigurationBase::~ConfigurationBase(void)
74 {
75 }
76 
77 //==============================================================================
78 std::string ConfigurationBase::getTypeId()
79 {
80  return typeid(this).name();
81 }
82 
83 //==============================================================================
84 void ConfigurationBase::init(ConfigurationManager *configurationManager)
85 {
86  //__MOUT__ << "Default ConfigurationBase::init() called." << std::endl;
87 }
88 
89 //==============================================================================
90 void ConfigurationBase::reset(bool keepTemporaryVersions)
91 {
92  //std::cout << __COUT_HDR_FL__ << "resetting" << std::endl;
93  deactivate();
94  if(keepTemporaryVersions)
95  trimCache(0);
96  else //clear all
97  configurationViews_.clear();
98 }
99 
100 //==============================================================================
101 void ConfigurationBase::print(std::ostream &out) const
102 {
103  //std::cout << __COUT_HDR_FL__ << "activeVersion_ " << activeVersion_ << " (INVALID_VERSION:=" << INVALID_VERSION << ")" << std::endl;
104  if(!activeConfigurationView_)
105  {
106  __MOUT_ERR__ << "ERROR: No active view set" << std::endl;
107  return;
108  }
109  activeConfigurationView_->print(out);
110 }
111 
112 //==============================================================================
113 // makes active version the specified configuration view version
114 // if the version is not already stored, then creates a mockup version
115 void ConfigurationBase::setupMockupView(ConfigurationVersion version)
116 {
117  if(!isStored(version))
118  {
119  configurationViews_[version].copy(mockupConfigurationView_,
120  version,
121  mockupConfigurationView_.getAuthor());
122  trimCache();
123  if(!isStored(version)) //the trim cache is misbehaving!
124  {
125  __SS__ << "\nsetupMockupView() IMPOSSIBLE ERROR: trimCache() is deleting the latest view version " <<
126  version << "!" << std::endl;
127  __MOUT_ERR__ << "\n" << ss.str();
128  throw std::runtime_error(ss.str());
129  }
130  }
131  else
132  {
133  __SS__ << "\nsetupMockupView() ERROR: View to fill with mockup already exists: " << version
134  << ". Cannot overwrite!" << std::endl;
135  __MOUT_ERR__ << "\n" << ss.str();
136  throw std::runtime_error(ss.str());
137  }
138 }
139 
140 
141 //==============================================================================
142 //trimCache
143 // if there are more views than MAX_VIEWS_IN_CACHE, erase them.
144 // choose wisely the view to delete
145 // (by access time)
146 void ConfigurationBase::trimCache(unsigned int trimSize)
147 {
148  //delete cached views, if necessary
149 
150  if(trimSize == (unsigned int)-1) //if -1, use MAX_VIEWS_IN_CACHE
151  trimSize = MAX_VIEWS_IN_CACHE;
152 
153  int i=0;
154  while(getNumberOfStoredViews() > trimSize)
155  {
156  ConfigurationVersion versionToDelete;
157  time_t stalestTime = -1;
158 
159  for(auto &viewPair : configurationViews_)
160  if(!viewPair.first.isTemporaryVersion())
161  {
162  if(stalestTime == -1 ||
163  viewPair.second.getLastAccessTime() < stalestTime)
164  {
165  versionToDelete = viewPair.first;
166  stalestTime = viewPair.second.getLastAccessTime();
167  if(!trimSize) break; //if trimSize is 0, then just take first found
168  }
169  }
170 
171  if(versionToDelete.isInvalid())
172  {
173  __SS__ << "Can NOT have a stored view with an invalid version!";
174  throw std::runtime_error(ss.str());
175  }
176 
177  eraseView(versionToDelete);
178  }
179 }
180 
181 //==============================================================================
182 //trimCache
183 // if there are more views than MAX_VIEWS_IN_CACHE, erase them.
184 // choose wisely the view to delete
185 // (by access time)
186 void ConfigurationBase::trimTemporary(ConfigurationVersion targetVersion)
187 {
188  if(targetVersion.isInvalid()) //erase all temporary
189  {
190  for(auto it = configurationViews_.begin(); it != configurationViews_.end(); /*no increment*/)
191  {
192  if(it->first.isTemporaryVersion())
193  {
194  __MOUT__ << "Trimming temporary version: " << it->first << std::endl;
195  if(activeConfigurationView_ &&
196  getViewVersion() == it->first) //if activeVersion is being erased!
197  deactivate(); //deactivate active view, instead of guessing at next active view
198  configurationViews_.erase(it++);
199  }
200  else
201  ++it;
202  }
203  }
204  else if(targetVersion.isTemporaryVersion()) //erase target
205  {
206  __MOUT__ << "Trimming temporary version: " << targetVersion << std::endl;
207  eraseView(targetVersion);
208  }
209  else
210  {
211  //else this is a persistent version!
212  __SS__ << "Temporary trim target was a persistent version: " <<
213  targetVersion << std::endl;
214  __MOUT_ERR__ << "\n" << ss.str();
215  throw std::runtime_error(ss.str());
216  }
217 }
218 
219 //==============================================================================
220 //checkForDuplicate
221 // look for a duplicate of the needleVersion in the haystack
222 // which is the cached views in configurationViews_
223 //
224 // Note: ignoreVersion is useful if you know another view is already identical
225 // like when converting from temporary to persistent
226 //
227 // Return invalid of no matches
228 ConfigurationVersion ConfigurationBase::checkForDuplicate(ConfigurationVersion needleVersion,
229  ConfigurationVersion ignoreVersion) const
230 {
231  auto needleIt = configurationViews_.find(needleVersion);
232  if(needleIt == configurationViews_.end())
233  {
234  //else this is a persistent version!
235  __SS__ << "needleVersion does not exist: " <<
236  needleVersion << std::endl;
237  __MOUT_ERR__ << "\n" << ss.str();
238  throw std::runtime_error(ss.str());
239  }
240 
241  const ConfigurationView *needleView = &(needleIt->second);
242  unsigned int rows = needleView->getNumberOfRows();
243  unsigned int cols = needleView->getNumberOfColumns();
244 
245  bool match;
246  //for each table in cache
247  // check each row,col
248  for(auto &viewPair: configurationViews_)
249  {
250  if(viewPair.first == needleVersion) continue; //skip needle version
251  if(viewPair.first == ignoreVersion) continue; //skip ignore version
252 
253  if(viewPair.second.getNumberOfRows() != rows)
254  continue; //row mismatch
255 
256  if(viewPair.second.getSourceColumnSize() != cols ||
257  viewPair.second.getSourceColumnMismatch() != 0)
258  continue; //col mismatch
259 
260 
261  match = true;
262 
263  auto srcColNameIt = viewPair.second.getSourceColumnNames().begin();
264  for(unsigned int col=0; match &&
265  col<viewPair.second.getSourceColumnNames().size()-3;++col,srcColNameIt++)
266  if(*srcColNameIt !=
267  needleView->getColumnsInfo()[col].getName())
268  match = false;
269 
270  for(unsigned int row=0;match && row<rows;++row)
271  {
272  for(unsigned int col=0;col<cols-2;++col) //do not consider author and timestamp
273  if(viewPair.second.getDataView()[row][col] !=
274  needleView->getDataView()[row][col])
275  { match = false; break; }
276  }
277  if(match)
278  {
279  __MOUT_INFO__ << "Duplicate version found: " << viewPair.first << std::endl;
280  return viewPair.first;
281  }
282  }
283 
284  return ConfigurationVersion(); //return invalid if no matches
285 }
286 
287 //==============================================================================
288 void ConfigurationBase::changeVersionAndActivateView(ConfigurationVersion temporaryVersion,
289  ConfigurationVersion version)
290 {
291  if(configurationViews_.find(temporaryVersion) == configurationViews_.end())
292  {
293  __SS__ << "ERROR: Temporary view version " << temporaryVersion << " doesn't exists!" << std::endl;
294  __MOUT_ERR__ << "\n" << ss.str();
295  throw std::runtime_error(ss.str());
296  }
297  if(version.isInvalid())
298  {
299  __SS__ << "ERROR: Attempting to create an invalid version " << version <<
300  "! Did you really run out of versions? (this should never happen)" << std::endl;
301  __MOUT_ERR__ << "\n" << ss.str();
302  throw std::runtime_error(ss.str());
303  }
304 
305  if(configurationViews_.find(version) != configurationViews_.end())
306  __MOUT_WARN__ << "WARNING: View version " << version << " already exists! Overwriting." << std::endl;
307 
308  configurationViews_[version].copy(configurationViews_[temporaryVersion],
309  version,
310  configurationViews_[temporaryVersion].getAuthor());
311  setActiveView(version);
312  eraseView(temporaryVersion); //delete temp version from configurationViews_
313 }
314 
315 //==============================================================================
316 bool ConfigurationBase::isStored(const ConfigurationVersion &version) const
317 {
318  return (configurationViews_.find(version) != configurationViews_.end());
319 }
320 
321 //==============================================================================
322 bool ConfigurationBase::eraseView(ConfigurationVersion version)
323 {
324  if(!isStored(version))
325  return false;
326 
327  if(activeConfigurationView_ &&
328  getViewVersion() == version) //if activeVersion is being erased!
329  deactivate(); //deactivate active view, instead of guessing at next active view
330 
331  configurationViews_.erase(version);
332 
333  return true;
334 }
335 
336 //==============================================================================
337 const std::string& ConfigurationBase::getConfigurationName(void) const
338 {
339  return configurationName_;
340 }
341 
342 //==============================================================================
343 const std::string& ConfigurationBase::getConfigurationDescription(void) const
344 {
345  return configurationDescription_;
346 }
347 
348 //==============================================================================
349 const ConfigurationVersion& ConfigurationBase::getViewVersion(void) const
350 {
351  return getView().getVersion();
352 }
353 
354 
355 //==============================================================================
356 //latestAndMockupColumnNumberMismatch
357 // intended to check if the column count was recently changed
358 bool ConfigurationBase::latestAndMockupColumnNumberMismatch(void) const
359 {
360  std::set<ConfigurationVersion> retSet = getStoredVersions();
361  if(retSet.size() && !retSet.rbegin()->isTemporaryVersion())
362  {
363  return configurationViews_.find(*(retSet.rbegin()))->second.getNumberOfColumns() !=
364  mockupConfigurationView_.getNumberOfColumns();
365  }
366  //there are no latest non-temporary tables so there is a mismatch (by default)
367  return true;
368 }
369 
370 //==============================================================================
371 std::set<ConfigurationVersion> ConfigurationBase::getStoredVersions(void) const
372 {
373  std::set<ConfigurationVersion> retSet;
374  for(auto &configs:configurationViews_)
375  retSet.emplace(configs.first);
376  return retSet;
377 }
378 
379 //==============================================================================
380 //getNumberOfStoredViews
381 // count number of stored views, not including temporary views
382 // (invalid views should be impossible)
383 unsigned int ConfigurationBase::getNumberOfStoredViews(void) const
384 {
385  unsigned int sz = 0;
386  for(auto &viewPair : configurationViews_)
387  if(viewPair.first.isTemporaryVersion()) continue;
388  else if(viewPair.first.isInvalid())
389  {
390  //__SS__ << "Can NOT have a stored view with an invalid version!";
391  //throw std::runtime_error(ss.str());
392 
393  //NOTE: if this starts happening a lot, could just auto-correct and remove the invalid version
394  // but it would be better to fix the cause.
395 
396  //FIXME... for now just auto correcting
397  __MOUT__ << "There is an invalid version now!.. where did it come from?" << std::endl;
398  }
399  else ++sz;
400  return sz;
401 }
402 
403 //==============================================================================
404 const ConfigurationView& ConfigurationBase::getView(void) const
405 {
406  if(!activeConfigurationView_)
407  {
408  __SS__ << "activeConfigurationView_ pointer is null! (...likely the active view was not setup properly. Check your system setup.)";
409  throw std::runtime_error(ss.str());
410  }
411  return *activeConfigurationView_;
412 }
413 
414 //==============================================================================
415 ConfigurationView* ConfigurationBase::getViewP(void)
416 {
417  if(!activeConfigurationView_)
418  {
419  __SS__ << "activeConfigurationView_ pointer is null! (...likely the active view was not setup properly. Check your system setup.)";
420  throw std::runtime_error(ss.str());
421  }
422  return activeConfigurationView_;
423 }
424 
425 //==============================================================================
426 ConfigurationView* ConfigurationBase::getMockupViewP(void)
427 {
428  return &mockupConfigurationView_;
429 }
430 
431 //==============================================================================
432 void ConfigurationBase::setConfigurationName(const std::string &configurationName)
433 {
434  configurationName_ = configurationName;
435 }
436 
437 //==============================================================================
438 void ConfigurationBase::setConfigurationDescription(const std::string &configurationDescription)
439 {
440  configurationDescription_ = configurationDescription;
441 }
442 
443 //==============================================================================
444 //deactivate
445 // reset the active view
446 void ConfigurationBase::deactivate()
447 {
448  activeConfigurationView_ = 0;
449 }
450 
451 //==============================================================================
452 //isActive
453 bool ConfigurationBase::isActive()
454 {
455  return activeConfigurationView_?true:false;
456 }
457 
458 //==============================================================================
459 bool ConfigurationBase::setActiveView(ConfigurationVersion version)
460 {
461  if(!isStored(version))
462  { //we don't call else load for the user, because the configuration manager would lose track.. (I think?)
463  //so load new versions for the first time through the configuration manager only. (I think??)
464  __SS__ << "\nsetActiveView() ERROR: View with version " << version <<
465  " has never been stored before!" << std::endl;
466  __MOUT_ERR__ << "\n" << ss.str();
467  throw std::runtime_error(ss.str());
468  return false;
469  }
470  activeConfigurationView_ = &configurationViews_[version];
471 
472  if(configurationViews_[version].getVersion() != version)
473  {
474  __SS__ << "Something has gone very wrong with the version handling!" << std::endl;
475  throw std::runtime_error(ss.str());
476  }
477 
478  return true;
479 }
480 
481 
482 //==============================================================================
483 //copyView
484 // copies source view (including version) and places in self
485 // as destination temporary version.
486 // if destination version is invalid, then next available temporary version is chosen
487 // if conflict, throw exception
488 //
489 // Returns version of new temporary view that was created.
490 ConfigurationVersion ConfigurationBase::copyView (const ConfigurationView &sourceView,
491  ConfigurationVersion destinationVersion, const std::string &author)
492 throw(std::runtime_error)
493 {
494  //check that column sizes match
495  if(sourceView.getNumberOfColumns() !=
496  mockupConfigurationView_.getNumberOfColumns())
497  {
498  __SS__ << "Error! Number of Columns of source view must match destination mock-up view." <<
499  "Dimension of source is [" << sourceView.getNumberOfColumns() <<
500  "] and of destination mockup is [" <<
501  mockupConfigurationView_.getNumberOfColumns() << "]." << std::endl;
502  throw std::runtime_error(ss.str());
503  }
504 
505  //check for destination version confict
506  if(!destinationVersion.isInvalid() &&
507  configurationViews_.find(sourceView.getVersion()) != configurationViews_.end())
508  {
509  __SS__ << "Error! Asked to copy a view with a conflicting version: " <<
510  sourceView.getVersion() << std::endl;
511  throw std::runtime_error(ss.str());
512  }
513 
514  //if destinationVersion is INVALID, creates next available temporary version
515  destinationVersion = createTemporaryView(ConfigurationVersion(),
516  destinationVersion);
517 
518  __MOUT__ << "Copying from " << sourceView.getTableName() << "_v" <<
519  sourceView.getVersion() << " to " << getConfigurationName() << "_v" <<
520  destinationVersion << std::endl;
521 
522  try
523  {
524  configurationViews_[destinationVersion].copy(sourceView,destinationVersion,author);
525  }
526  catch(...) //if the copy fails then delete the destinationVersion view
527  {
528  __MOUT_ERR__ << "Failed to copy from " << sourceView.getTableName() << "_v" <<
529  sourceView.getVersion() << " to " << getConfigurationName() << "_v" <<
530  destinationVersion << std::endl;
531  __MOUT_WARN__ << "Deleting the failed destination version " <<
532  destinationVersion << std::endl;
533  eraseView(destinationVersion);
534  throw; //and rethrow
535  }
536  return destinationVersion;
537 }
538 
539 
540 //==============================================================================
541 //createTemporaryView
542 // -1, from MockUp, else from valid view version
543 // destTemporaryViewVersion is starting point for search for available temporary versions.
544 // if destTemporaryViewVersion is invalid, starts search at ConfigurationVersion::getNextTemporaryVersion().
545 // returns new temporary version number (which is always negative)
546 ConfigurationVersion ConfigurationBase::createTemporaryView(ConfigurationVersion sourceViewVersion,
547  ConfigurationVersion destTemporaryViewVersion)
548 {
549  __MOUT__ << "Configuration: " <<
550  getConfigurationName()<< std::endl;
551 
552  __MOUT__ << "Num of Views: " <<
553  configurationViews_.size() << " (Temporary Views: " <<
554  (configurationViews_.size() - getNumberOfStoredViews()) << ")" << std::endl;
555 
556  ConfigurationVersion tmpVersion = destTemporaryViewVersion;
557  if(tmpVersion.isInvalid()) tmpVersion = ConfigurationVersion::getNextTemporaryVersion();
558  while(isStored(tmpVersion) && //find a new valid temporary version
559  !(tmpVersion = ConfigurationVersion::getNextTemporaryVersion(tmpVersion)).isInvalid());
560  if(isStored(tmpVersion) || tmpVersion.isInvalid())
561  {
562  __MOUT_ERR__ << "Invalid destination temporary version: " <<
563  destTemporaryViewVersion << ". Expected next temporary version < " << tmpVersion << std::endl;
564  throw std::runtime_error("Invalid temporary version destination");
565  }
566 
567  if(sourceViewVersion == ConfigurationVersion::INVALID || //use mockup if sourceVersion is -1 or not found
568  configurationViews_.find(sourceViewVersion) == configurationViews_.end())
569  {
570  if(sourceViewVersion != -1)
571  {
572  __MOUT_ERR__ << "ERROR: sourceViewVersion " << sourceViewVersion << " not found" << std::endl;
573  throw std::runtime_error("Invalid source version. Version requested is not stored (yet?) or does not exist.");
574  }
575  __MOUT__ << "Using Mock-up view" << std::endl;
576  configurationViews_[tmpVersion].copy(mockupConfigurationView_,
577  tmpVersion,
578  mockupConfigurationView_.getAuthor());
579  }
580  else
581  {
582  try //do not allow init to throw an exception here..
583  { //it's ok to copy invalid data, the user may be trying to change it
584  configurationViews_[tmpVersion].copy(configurationViews_[sourceViewVersion],
585  tmpVersion,
586  configurationViews_[sourceViewVersion].getAuthor());
587  }
588  catch(...)
589  {
590  __MOUT_WARN__ << "createTemporaryView() Source view failed init(). " <<
591  "This is being ignored (hopefully the new copy is being fixed)." << std::endl;
592  }
593  }
594 
595  return tmpVersion;
596 }
597 
598 //==============================================================================
599 //getNextAvailableTemporaryView
600 // ConfigurationVersion::INVALID is always MockUp
601 // returns next available temporary version number (which is always negative)
602 ConfigurationVersion ConfigurationBase::getNextTemporaryVersion() const
603 {
604  ConfigurationVersion tmpVersion;
605 
606  //std::map guarantees versions are in increasing order!
607  if(configurationViews_.size() != 0 && configurationViews_.begin()->first.isTemporaryVersion())
608  tmpVersion =
609  ConfigurationVersion::getNextTemporaryVersion(configurationViews_.begin()->first);
610  else
611  tmpVersion = ConfigurationVersion::getNextTemporaryVersion();
612 
613  //verify tmpVersion is ok
614  if(isStored(tmpVersion) || tmpVersion.isInvalid() || !tmpVersion.isTemporaryVersion())
615  {
616  __MOUT_ERR__ << "Invalid destination temporary version: " <<
617  tmpVersion << std::endl;
618  throw std::runtime_error("Invalid temporary version found");
619  }
620  return tmpVersion;
621 }
622 
623 //==============================================================================
624 //getNextVersion
625 // returns next available new version
626 // the implication is any version number equal or greater is available.
627 ConfigurationVersion ConfigurationBase::getNextVersion() const
628 {
629  ConfigurationVersion tmpVersion;
630 
631  //std::map guarantees versions are in increasing order!
632  if(configurationViews_.size() != 0 && !configurationViews_.rbegin()->first.isTemporaryVersion())
633  tmpVersion =
634  ConfigurationVersion::getNextVersion(configurationViews_.rbegin()->first);
635  else
636  tmpVersion = ConfigurationVersion::getNextVersion();
637 
638  //verify tmpVersion is ok
639  if(isStored(tmpVersion) || tmpVersion.isInvalid() || tmpVersion.isTemporaryVersion())
640  {
641  __MOUT_ERR__ << "Invalid destination next version: " <<
642  tmpVersion << std::endl;
643  throw std::runtime_error("Invalid next version found");
644  }
645  return tmpVersion;
646 }
647 
648 //==============================================================================
649 //getTemporaryView
650 // must be a valid temporary version, and the view must be stored in configuration.
651 // temporary version indicates it has not been saved to database and assigned a version number
652 ConfigurationView* ConfigurationBase::getTemporaryView(ConfigurationVersion temporaryVersion)
653 {
654  if(!temporaryVersion.isTemporaryVersion() ||
655  !isStored(temporaryVersion))
656  {
657  __MOUT_ERR__ << getConfigurationName() << ":: Error! Temporary version not found!" << std::endl;
658  throw std::runtime_error("Invalid temporary version");
659  }
660  return &configurationViews_[temporaryVersion];
661 }
662 
663 
664 //==============================================================================
665 //convertToCaps
666 // static utility for converting configuration and column names to the caps version
667 // throw std::runtime_error if not completely alpha-numeric input
668 std::string ConfigurationBase::convertToCaps(std::string& str, bool isConfigName)
669 throw(std::runtime_error)
670 {
671  //append Configuration to be nice to user
672  unsigned int configPos = (unsigned int)std::string::npos;
673  if(isConfigName && (configPos = str.find("Configuration")) !=
674  str.size() - strlen("Configuration"))
675  str += "Configuration";
676 
677  //std::cout << str << std::endl;
678  //std::cout << configPos << " " << (str.size() - strlen("Configuration")) << std::endl;
679 
680  //create all caps name and validate
681  // only allow alpha names with Configuration at end
682  std::string capsStr = "";
683  for(unsigned int c=0;c<str.size();++c)
684  if(str[c] >= 'A' && str[c] <= 'Z')
685  {
686  //add _ before configuration and if lower case to uppercase
687  if(c == configPos ||
688  (c && str[c-1] >= 'a' && str[c-1] <= 'z') || //if this is a new start of upper case
689  (c && str[c-1] >= 'A' && str[c-1] <= 'Z' && //if this is a new start from running caps
690  c+1 < str.size() && str[c+1] >= 'a' && str[c+1] <= 'z')
691  )
692  capsStr += "_";
693  capsStr += str[c];
694  }
695  else if(str[c] >= 'a' && str[c] <= 'z')
696  capsStr += char(str[c] -32); //capitalize
697  else if(str[c] >= '0' && str[c] <= '9')
698  capsStr += str[c]; //allow numbers
699  else //error! non-alpha
700  throw std::runtime_error(std::string("ConfigurationBase::convertToCaps::") +
701  "Invalid character found in name (allowed: A-Z, a-z, 0-9):" +
702  str );
703 
704  return capsStr;
705 }
706 
707 
708 
709