otsdaq  v1_01_03
 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 if 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.getDataColumnSize() != 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  viewPair.second.getSourceColumnNames().size() > 3 &&
266  col<viewPair.second.getSourceColumnNames().size()-3;++col,srcColNameIt++)
267  if(*srcColNameIt !=
268  needleView->getColumnsInfo()[col].getName())
269  match = false;
270 
271  for(unsigned int row=0;match && row<rows;++row)
272  {
273  for(unsigned int col=0;col<cols-2;++col) //do not consider author and timestamp
274  if(viewPair.second.getDataView()[row][col] !=
275  needleView->getDataView()[row][col])
276  { match = false; break; }
277  }
278  if(match)
279  {
280  __MOUT_INFO__ << "Duplicate version found: " << viewPair.first << std::endl;
281  return viewPair.first;
282  }
283  }
284 
285  return ConfigurationVersion(); //return invalid if no matches
286 }
287 
288 //==============================================================================
289 void ConfigurationBase::changeVersionAndActivateView(ConfigurationVersion temporaryVersion,
290  ConfigurationVersion version)
291 {
292  if(configurationViews_.find(temporaryVersion) == configurationViews_.end())
293  {
294  __SS__ << "ERROR: Temporary view version " << temporaryVersion << " doesn't exists!" << std::endl;
295  __MOUT_ERR__ << "\n" << ss.str();
296  throw std::runtime_error(ss.str());
297  }
298  if(version.isInvalid())
299  {
300  __SS__ << "ERROR: Attempting to create an invalid version " << version <<
301  "! Did you really run out of versions? (this should never happen)" << std::endl;
302  __MOUT_ERR__ << "\n" << ss.str();
303  throw std::runtime_error(ss.str());
304  }
305 
306  if(configurationViews_.find(version) != configurationViews_.end())
307  __MOUT_WARN__ << "WARNING: View version " << version << " already exists! Overwriting." << std::endl;
308 
309  configurationViews_[version].copy(configurationViews_[temporaryVersion],
310  version,
311  configurationViews_[temporaryVersion].getAuthor());
312  setActiveView(version);
313  eraseView(temporaryVersion); //delete temp version from configurationViews_
314 }
315 
316 //==============================================================================
317 bool ConfigurationBase::isStored(const ConfigurationVersion &version) const
318 {
319  return (configurationViews_.find(version) != configurationViews_.end());
320 }
321 
322 //==============================================================================
323 bool ConfigurationBase::eraseView(ConfigurationVersion version)
324 {
325  if(!isStored(version))
326  return false;
327 
328  if(activeConfigurationView_ &&
329  getViewVersion() == version) //if activeVersion is being erased!
330  deactivate(); //deactivate active view, instead of guessing at next active view
331 
332  configurationViews_.erase(version);
333 
334  return true;
335 }
336 
337 //==============================================================================
338 const std::string& ConfigurationBase::getConfigurationName(void) const
339 {
340  return configurationName_;
341 }
342 
343 //==============================================================================
344 const std::string& ConfigurationBase::getConfigurationDescription(void) const
345 {
346  return configurationDescription_;
347 }
348 
349 //==============================================================================
350 const ConfigurationVersion& ConfigurationBase::getViewVersion(void) const
351 {
352  return getView().getVersion();
353 }
354 
355 
356 //==============================================================================
357 //latestAndMockupColumnNumberMismatch
358 // intended to check if the column count was recently changed
359 bool ConfigurationBase::latestAndMockupColumnNumberMismatch(void) const
360 {
361  std::set<ConfigurationVersion> retSet = getStoredVersions();
362  if(retSet.size() && !retSet.rbegin()->isTemporaryVersion())
363  {
364  return configurationViews_.find(*(retSet.rbegin()))->second.getNumberOfColumns() !=
365  mockupConfigurationView_.getNumberOfColumns();
366  }
367  //there are no latest non-temporary tables so there is a mismatch (by default)
368  return true;
369 }
370 
371 //==============================================================================
372 std::set<ConfigurationVersion> ConfigurationBase::getStoredVersions(void) const
373 {
374  std::set<ConfigurationVersion> retSet;
375  for(auto &configs:configurationViews_)
376  retSet.emplace(configs.first);
377  return retSet;
378 }
379 
380 //==============================================================================
381 //getNumberOfStoredViews
382 // count number of stored views, not including temporary views
383 // (invalid views should be impossible)
384 unsigned int ConfigurationBase::getNumberOfStoredViews(void) const
385 {
386  unsigned int sz = 0;
387  for(auto &viewPair : configurationViews_)
388  if(viewPair.first.isTemporaryVersion()) continue;
389  else if(viewPair.first.isInvalid())
390  {
391  //__SS__ << "Can NOT have a stored view with an invalid version!";
392  //throw std::runtime_error(ss.str());
393 
394  //NOTE: if this starts happening a lot, could just auto-correct and remove the invalid version
395  // but it would be better to fix the cause.
396 
397  //FIXME... for now just auto correcting
398  __MOUT__ << "There is an invalid version now!.. where did it come from?" << std::endl;
399  }
400  else ++sz;
401  return sz;
402 }
403 
404 //==============================================================================
405 const ConfigurationView& ConfigurationBase::getView(void) const
406 {
407  if(!activeConfigurationView_)
408  {
409  __SS__ << "activeConfigurationView_ pointer is null! (...likely the active view was not setup properly. Check your system setup.)";
410  throw std::runtime_error(ss.str());
411  }
412  return *activeConfigurationView_;
413 }
414 
415 //==============================================================================
416 ConfigurationView* ConfigurationBase::getViewP(void)
417 {
418  if(!activeConfigurationView_)
419  {
420  __SS__ << "activeConfigurationView_ pointer is null! (...likely the active view was not setup properly. Check your system setup.)";
421  throw std::runtime_error(ss.str());
422  }
423  return activeConfigurationView_;
424 }
425 
426 //==============================================================================
427 ConfigurationView* ConfigurationBase::getMockupViewP(void)
428 {
429  return &mockupConfigurationView_;
430 }
431 
432 //==============================================================================
433 void ConfigurationBase::setConfigurationName(const std::string &configurationName)
434 {
435  configurationName_ = configurationName;
436 }
437 
438 //==============================================================================
439 void ConfigurationBase::setConfigurationDescription(const std::string &configurationDescription)
440 {
441  configurationDescription_ = configurationDescription;
442 }
443 
444 //==============================================================================
445 //deactivate
446 // reset the active view
447 void ConfigurationBase::deactivate()
448 {
449  activeConfigurationView_ = 0;
450 }
451 
452 //==============================================================================
453 //isActive
454 bool ConfigurationBase::isActive()
455 {
456  return activeConfigurationView_?true:false;
457 }
458 
459 //==============================================================================
460 bool ConfigurationBase::setActiveView(ConfigurationVersion version)
461 {
462  if(!isStored(version))
463  { //we don't call else load for the user, because the configuration manager would lose track.. (I think?)
464  //so load new versions for the first time through the configuration manager only. (I think??)
465  __SS__ << "\nsetActiveView() ERROR: View with version " << version <<
466  " has never been stored before!" << std::endl;
467  __MOUT_ERR__ << "\n" << ss.str();
468  throw std::runtime_error(ss.str());
469  return false;
470  }
471  activeConfigurationView_ = &configurationViews_[version];
472 
473  if(configurationViews_[version].getVersion() != version)
474  {
475  __SS__ << "Something has gone very wrong with the version handling!" << std::endl;
476  throw std::runtime_error(ss.str());
477  }
478 
479  return true;
480 }
481 
482 
483 //==============================================================================
484 //copyView
485 // copies source view (including version) and places in self
486 // as destination temporary version.
487 // if destination version is invalid, then next available temporary version is chosen
488 // if conflict, throw exception
489 //
490 // Returns version of new temporary view that was created.
491 ConfigurationVersion ConfigurationBase::copyView (const ConfigurationView &sourceView,
492  ConfigurationVersion destinationVersion, const std::string &author)
493 throw(std::runtime_error)
494 {
495  //check that column sizes match
496  if(sourceView.getNumberOfColumns() !=
497  mockupConfigurationView_.getNumberOfColumns())
498  {
499  __SS__ << "Error! Number of Columns of source view must match destination mock-up view." <<
500  "Dimension of source is [" << sourceView.getNumberOfColumns() <<
501  "] and of destination mockup is [" <<
502  mockupConfigurationView_.getNumberOfColumns() << "]." << std::endl;
503  throw std::runtime_error(ss.str());
504  }
505 
506  //check for destination version confict
507  if(!destinationVersion.isInvalid() &&
508  configurationViews_.find(sourceView.getVersion()) != configurationViews_.end())
509  {
510  __SS__ << "Error! Asked to copy a view with a conflicting version: " <<
511  sourceView.getVersion() << std::endl;
512  throw std::runtime_error(ss.str());
513  }
514 
515  //if destinationVersion is INVALID, creates next available temporary version
516  destinationVersion = createTemporaryView(ConfigurationVersion(),
517  destinationVersion);
518 
519  __MOUT__ << "Copying from " << sourceView.getTableName() << "_v" <<
520  sourceView.getVersion() << " to " << getConfigurationName() << "_v" <<
521  destinationVersion << std::endl;
522 
523  try
524  {
525  configurationViews_[destinationVersion].copy(sourceView,destinationVersion,author);
526  }
527  catch(...) //if the copy fails then delete the destinationVersion view
528  {
529  __MOUT_ERR__ << "Failed to copy from " << sourceView.getTableName() << "_v" <<
530  sourceView.getVersion() << " to " << getConfigurationName() << "_v" <<
531  destinationVersion << std::endl;
532  __MOUT_WARN__ << "Deleting the failed destination version " <<
533  destinationVersion << std::endl;
534  eraseView(destinationVersion);
535  throw; //and rethrow
536  }
537  return destinationVersion;
538 }
539 
540 
541 //==============================================================================
542 //createTemporaryView
543 // -1, from MockUp, else from valid view version
544 // destTemporaryViewVersion is starting point for search for available temporary versions.
545 // if destTemporaryViewVersion is invalid, starts search at ConfigurationVersion::getNextTemporaryVersion().
546 // returns new temporary version number (which is always negative)
547 ConfigurationVersion ConfigurationBase::createTemporaryView(ConfigurationVersion sourceViewVersion,
548  ConfigurationVersion destTemporaryViewVersion)
549 {
550  __MOUT__ << "Configuration: " <<
551  getConfigurationName()<< std::endl;
552 
553  __MOUT__ << "Num of Views: " <<
554  configurationViews_.size() << " (Temporary Views: " <<
555  (configurationViews_.size() - getNumberOfStoredViews()) << ")" << std::endl;
556 
557  ConfigurationVersion tmpVersion = destTemporaryViewVersion;
558  if(tmpVersion.isInvalid()) tmpVersion = ConfigurationVersion::getNextTemporaryVersion();
559  while(isStored(tmpVersion) && //find a new valid temporary version
560  !(tmpVersion = ConfigurationVersion::getNextTemporaryVersion(tmpVersion)).isInvalid());
561  if(isStored(tmpVersion) || tmpVersion.isInvalid())
562  {
563  __MOUT_ERR__ << "Invalid destination temporary version: " <<
564  destTemporaryViewVersion << ". Expected next temporary version < " << tmpVersion << std::endl;
565  throw std::runtime_error("Invalid temporary version destination");
566  }
567 
568  if(sourceViewVersion == ConfigurationVersion::INVALID || //use mockup if sourceVersion is -1 or not found
569  configurationViews_.find(sourceViewVersion) == configurationViews_.end())
570  {
571  if(sourceViewVersion != -1)
572  {
573  __MOUT_ERR__ << "ERROR: sourceViewVersion " << sourceViewVersion << " not found" << std::endl;
574  throw std::runtime_error("Invalid source version. Version requested is not stored (yet?) or does not exist.");
575  }
576  __MOUT__ << "Using Mock-up view" << std::endl;
577  configurationViews_[tmpVersion].copy(mockupConfigurationView_,
578  tmpVersion,
579  mockupConfigurationView_.getAuthor());
580  }
581  else
582  {
583  try //do not allow init to throw an exception here..
584  { //it's ok to copy invalid data, the user may be trying to change it
585  configurationViews_[tmpVersion].copy(configurationViews_[sourceViewVersion],
586  tmpVersion,
587  configurationViews_[sourceViewVersion].getAuthor());
588  }
589  catch(...)
590  {
591  __MOUT_WARN__ << "createTemporaryView() Source view failed init(). " <<
592  "This is being ignored (hopefully the new copy is being fixed)." << std::endl;
593  }
594  }
595 
596  return tmpVersion;
597 }
598 
599 //==============================================================================
600 //getNextAvailableTemporaryView
601 // ConfigurationVersion::INVALID is always MockUp
602 // returns next available temporary version number (which is always negative)
603 ConfigurationVersion ConfigurationBase::getNextTemporaryVersion() const
604 {
605  ConfigurationVersion tmpVersion;
606 
607  //std::map guarantees versions are in increasing order!
608  if(configurationViews_.size() != 0 && configurationViews_.begin()->first.isTemporaryVersion())
609  tmpVersion =
610  ConfigurationVersion::getNextTemporaryVersion(configurationViews_.begin()->first);
611  else
612  tmpVersion = ConfigurationVersion::getNextTemporaryVersion();
613 
614  //verify tmpVersion is ok
615  if(isStored(tmpVersion) || tmpVersion.isInvalid() || !tmpVersion.isTemporaryVersion())
616  {
617  __MOUT_ERR__ << "Invalid destination temporary version: " <<
618  tmpVersion << std::endl;
619  throw std::runtime_error("Invalid temporary version found");
620  }
621  return tmpVersion;
622 }
623 
624 //==============================================================================
625 //getNextVersion
626 // returns next available new version
627 // the implication is any version number equal or greater is available.
628 ConfigurationVersion ConfigurationBase::getNextVersion() const
629 {
630  ConfigurationVersion tmpVersion;
631 
632  //std::map guarantees versions are in increasing order!
633  if(configurationViews_.size() != 0 && !configurationViews_.rbegin()->first.isTemporaryVersion())
634  tmpVersion =
635  ConfigurationVersion::getNextVersion(configurationViews_.rbegin()->first);
636  else
637  tmpVersion = ConfigurationVersion::getNextVersion();
638 
639  //verify tmpVersion is ok
640  if(isStored(tmpVersion) || tmpVersion.isInvalid() || tmpVersion.isTemporaryVersion())
641  {
642  __MOUT_ERR__ << "Invalid destination next version: " <<
643  tmpVersion << std::endl;
644  throw std::runtime_error("Invalid next version found");
645  }
646  return tmpVersion;
647 }
648 
649 //==============================================================================
650 //getTemporaryView
651 // must be a valid temporary version, and the view must be stored in configuration.
652 // temporary version indicates it has not been saved to database and assigned a version number
653 ConfigurationView* ConfigurationBase::getTemporaryView(ConfigurationVersion temporaryVersion)
654 {
655  if(!temporaryVersion.isTemporaryVersion() ||
656  !isStored(temporaryVersion))
657  {
658  __MOUT_ERR__ << getConfigurationName() << ":: Error! Temporary version not found!" << std::endl;
659  throw std::runtime_error("Invalid temporary version");
660  }
661  return &configurationViews_[temporaryVersion];
662 }
663 
664 
665 //==============================================================================
666 //convertToCaps
667 // static utility for converting configuration and column names to the caps version
668 // throw std::runtime_error if not completely alpha-numeric input
669 std::string ConfigurationBase::convertToCaps(std::string& str, bool isConfigName)
670 throw(std::runtime_error)
671 {
672  //append Configuration to be nice to user
673  unsigned int configPos = (unsigned int)std::string::npos;
674  if(isConfigName && (configPos = str.find("Configuration")) !=
675  str.size() - strlen("Configuration"))
676  str += "Configuration";
677 
678  //std::cout << str << std::endl;
679  //std::cout << configPos << " " << (str.size() - strlen("Configuration")) << std::endl;
680 
681  //create all caps name and validate
682  // only allow alpha names with Configuration at end
683  std::string capsStr = "";
684  for(unsigned int c=0;c<str.size();++c)
685  if(str[c] >= 'A' && str[c] <= 'Z')
686  {
687  //add _ before configuration and if lower case to uppercase
688  if(c == configPos ||
689  (c && str[c-1] >= 'a' && str[c-1] <= 'z') || //if this is a new start of upper case
690  (c && str[c-1] >= 'A' && str[c-1] <= 'Z' && //if this is a new start from running caps
691  c+1 < str.size() && str[c+1] >= 'a' && str[c+1] <= 'z')
692  )
693  capsStr += "_";
694  capsStr += str[c];
695  }
696  else if(str[c] >= 'a' && str[c] <= 'z')
697  capsStr += char(str[c] -32); //capitalize
698  else if(str[c] >= '0' && str[c] <= '9')
699  capsStr += str[c]; //allow numbers
700  else //error! non-alpha
701  throw std::runtime_error(std::string("ConfigurationBase::convertToCaps::") +
702  "Invalid character found in name (allowed: A-Z, a-z, 0-9):" +
703  str );
704 
705  return capsStr;
706 }
707 
708 
709 
710