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