otsdaq  3.03.00
ConfigurationSupervisorBase.cc
1 #include "otsdaq/CoreSupervisors/ConfigurationSupervisorBase.h"
2 #include "otsdaq/TablePlugins/XDAQContextTable/XDAQContextTable.h"
3 
4 using namespace ots;
5 
6 //==============================================================================
9  HttpXmlDocument& xmlOut, ConfigurationManagerRW* cfgMgr, const std::string& username)
10 {
11  std::map<std::string /*type*/, std::pair<std::string /*groupName*/, TableGroupKey>>
12  activeGroupMap = cfgMgr->getActiveTableGroups();
13 
14  for(auto& type : activeGroupMap)
15  {
16  xmlOut.addTextElementToData(type.first + "-ActiveGroupName", type.second.first);
17  xmlOut.addTextElementToData(type.first + "-ActiveGroupKey",
18  type.second.second.toString());
19  //__SUP_COUT__ << "ActiveGroup " << type.first << " " << type.second.first << "("
20  //<< type.second.second << ")" << __E__;
21  }
22  try // try to get matching group alias for active groups
23  {
24  std::map<std::string, TableVersion> activeVersions = cfgMgr->getActiveVersions();
25  std::string groupAliasesTableName =
26  ConfigurationManager::GROUP_ALIASES_TABLE_NAME;
27  if(activeVersions.find(groupAliasesTableName) != activeVersions.end())
28  {
29  // have an active group aliases table at this point
30  std::vector<std::pair<std::string, ConfigurationTree>> aliasNodePairs =
31  cfgMgr->getNode(groupAliasesTableName).getChildren();
32 
33  std::string groupName, groupKey, groupComment, groupType;
34  std::string activeGroupName, activeGroupKey;
35  for(auto& type : activeGroupMap)
36  {
37  activeGroupName = type.second.first;
38  activeGroupKey = type.second.second.toString();
39  for(auto& aliasNodePair : aliasNodePairs)
40  {
41  groupName =
42  aliasNodePair.second.getNode("GroupName").getValueAsString();
43  groupKey =
44  aliasNodePair.second.getNode("GroupKey").getValueAsString();
45  if(groupName == activeGroupName && groupKey == activeGroupKey)
46  { // found match!
47  xmlOut.addTextElementToData(type.first + "-ActiveGroupAlias",
48  aliasNodePair.first);
49  break;
50  }
51  } // end alias match search loop
52  } // end active group loop
53  } // end handling of matching group alias to active groups
54  // else ignore missing active group alias table or active backbone
55  }
56  catch(...)
57  {
58  __COUT__ << "Ignoring failure getting alias for active groups" << __E__;
59  }
60 
61  // always add version tracking bool
62  xmlOut.addTextElementToData(
63  "versionTracking",
64  ConfigurationInterface::isVersionTrackingEnabled() ? "ON" : "OFF");
65 
66  xmlOut.addTextElementToData("configUsername", username);
67 
68 } // end getConfigurationStatusXML()
69 
70 //==============================================================================
79  ConfigurationManagerRW* cfgMgr,
80  const std::string& tableName,
81  TableVersion version,
82  bool makeTemporary,
83  const std::string& data,
84  const int& dataOffset,
85  const std::string& author,
86  const std::string& comment,
87  bool sourceTableAsIs,
88  bool lookForEquivalent)
89 try
90 {
91  //__COUT__ << "handleCreateTableXML: " << tableName << " version: " <<
92  // version
93  // << " dataOffset: " << dataOffset << __E__;
94 
95  //__COUT__ << "data: " << data << __E__;
96 
97  // create temporary version from starting version
98  if(!version.isInvalid()) // if not using mock-up, make sure starting version is
99  // loaded
100  {
101  try
102  {
103  cfgMgr->getVersionedTableByName(tableName, version);
104  }
105  catch(...)
106  {
107  // force to mockup
108  version = TableVersion();
109  }
110  }
111 
112  TableBase* table = cfgMgr->getTableByName(tableName);
113 
114  // check that the source version has the right number of columns
115  // if there is a mismatch, start from mockup
116  if(!version.isInvalid()) // if not using mock-up, then the starting version is the
117  // active one
118  {
119  // compare active to mockup column counts
120  if(table->getViewP()->getDataColumnSize() !=
121  table->getMockupViewP()->getNumberOfColumns() ||
122  table->getViewP()->getSourceColumnMismatch() != 0)
123  {
124  __COUT__ << "table->getViewP()->getNumberOfColumns() "
125  << table->getViewP()->getNumberOfColumns() << __E__;
126  __COUT__ << "table->getMockupViewP()->getNumberOfColumns() "
127  << table->getMockupViewP()->getNumberOfColumns() << __E__;
128  __COUT__ << "table->getViewP()->getSourceColumnMismatch() "
129  << table->getViewP()->getSourceColumnMismatch() << __E__;
130  __COUT_INFO__
131  << "Source view v" << version
132  << " has a mismatch in the number of columns, so using mockup as source."
133  << __E__;
134  version = TableVersion(); // invalid = mockup
135  }
136  }
137 
138  bool ignoreDuplicates = false;
139  if(!version.isTemporaryVersion() && sourceTableAsIs &&
140  table->getViewP()->getSourceColumnNames().size() !=
141  table->getViewP()->getDataColumnSize())
142  {
143  __COUT__ << "table->getViewP()->getNumberOfColumns() "
144  << table->getViewP()->getNumberOfColumns() << __E__;
145  __COUTV__(table->getViewP()->getSourceColumnNames().size());
146  __COUT_INFO__
147  << "Source view v" << version
148  << " has a mismatch in the number of columns, so forcing new version saved."
149  << __E__;
150  ignoreDuplicates = true;
151  }
152 
153  // create a temporary version from the source version
154  TableVersion temporaryVersion = table->createTemporaryView(version);
155 
156  __COUT__ << "\t\ttemporaryVersion: " << temporaryVersion << __E__;
157 
158  TableView* cfgView = table->getTemporaryView(temporaryVersion);
159 
160  int retVal;
161  try
162  {
163  // returns -1 on error that data was unchanged
164  retVal =
165  sourceTableAsIs ? 0 : cfgView->fillFromEncodedCSV(data, dataOffset, author);
166 
167  if(retVal == 1) // data was same but columns are different!
168  {
169  __COUT__ << "Data was the same, but columns have changed!" << __E__;
170  __COUTV__(sourceTableAsIs);
171  __COUTV__(lookForEquivalent);
172  }
173 
174  cfgView->setURIEncodedComment(comment);
175  __COUT__ << "Table comment was set to:\n\t" << cfgView->getComment() << __E__;
176  }
177  catch(...) // erase temporary view before re-throwing error
178  {
179  __COUT__ << "Caught error while editing. Erasing temporary version." << __E__;
180  table->eraseView(temporaryVersion);
181  throw;
182  }
183 
184  // Note: be careful with any further table operations at this point..
185  // must catch errors and erase temporary version on failure.
186 
187  // only consider it an error if source version was persistent version
188  // allow it if source version is temporary and we are making a persistent version now
189  // also, allow it if version tracking is off.
190  if(retVal < 0 && (!version.isTemporaryVersion() || makeTemporary) &&
191  ConfigurationInterface::isVersionTrackingEnabled())
192  {
193  if(!version.isInvalid() && // if source version was mockup, then consider it
194  // attempt to create a blank table
195  !version.isScratchVersion()) // if source version was scratch, then consider
196  // it attempt to make it persistent
197  {
198  __SS__ << "No rows were modified! No reason to fill a view with same content."
199  << __E__;
200  __COUT_ERR__ << "\n" << ss.str();
201  // delete temporaryVersion
202  table->eraseView(temporaryVersion);
203  __SS_THROW__;
204  }
205  else if(version.isInvalid())
206  __COUT__ << "This was interpreted as an attempt to create a blank table."
207  << __E__;
208  else if(version.isScratchVersion())
209  __COUT__ << "This was interpreted as an attempt to make a persistent "
210  "version of the scratch table."
211  << __E__;
212  else
213  {
214  __SS__;
215  __THROW__(ss.str() + "impossible!");
216  }
217  }
218  else if(retVal < 0 && (version.isTemporaryVersion() && !makeTemporary))
219  {
220  __COUT__ << "Allowing the static data because this is converting from "
221  "temporary to persistent version."
222  << __E__;
223  }
224  else if(retVal < 0 && !ConfigurationInterface::isVersionTrackingEnabled())
225  {
226  __COUT__ << "Allowing the static data because version tracking is OFF." << __E__;
227  }
228  else if(retVal < 0)
229  {
230  __SS__ << "This should not be possible! Fatal error." << __E__;
231  // delete temporaryVersion
232  table->eraseView(temporaryVersion);
233  __SS_THROW__;
234  }
235 
236  // note: if sourceTableAsIs, accept equivalent versions
238  xmlOut,
239  cfgMgr,
240  tableName,
241  version,
242  makeTemporary,
243  table,
244  temporaryVersion,
245  ignoreDuplicates /*ignoreDuplicates*/,
246  lookForEquivalent || sourceTableAsIs /*lookForEquivalent*/);
247 
248  if(ignoreDuplicates && sourceTableAsIs) // reset cache for this table
249  {
250  table = cfgMgr->getTableByName(tableName);
251  table->eraseView(newVersion);
252  }
253 } // end handleCreateTableXML()
254 catch(std::runtime_error& e)
255 {
256  __SS__ << "Error saving new table!\n\n " << e.what() << __E__;
257  __COUT__ << "\n" << ss.str() << __E__;
258  xmlOut.addTextElementToData("Error", ss.str());
259 }
260 catch(...)
261 {
262  __SS__ << "Error saving new table!" << __E__;
263  try
264  {
265  throw;
266  } //one more try to printout extra info
267  catch(const std::exception& e)
268  {
269  ss << "Exception message: " << e.what();
270  }
271  catch(...)
272  {
273  }
274  __COUT__ << "\n" << ss.str() << __E__;
275  xmlOut.addTextElementToData("Error", ss.str());
276 } // end handleCreateTableXML() catch
277 
278 //==============================================================================
284  HttpXmlDocument& xmlOut,
285  ConfigurationManagerRW* cfgMgr,
286  const std::string& tableName,
287  TableVersion originalVersion,
288  bool makeTemporary,
289  TableBase* table,
290  TableVersion temporaryModifiedVersion,
291  bool ignoreDuplicates,
292  bool lookForEquivalent)
293 {
294  bool foundEquivalent;
295  TableVersion newAssignedVersion =
296  cfgMgr->saveModifiedVersion(tableName,
297  originalVersion,
298  makeTemporary,
299  table,
300  temporaryModifiedVersion,
301  ignoreDuplicates,
302  lookForEquivalent,
303  &foundEquivalent);
304 
305  xmlOut.addTextElementToData("savedName", tableName);
306  xmlOut.addTextElementToData("savedVersion", newAssignedVersion.toString());
307 
308  if(foundEquivalent)
309  {
310  xmlOut.addTextElementToData("foundEquivalentVersion", "1");
311  xmlOut.addTextElementToData(tableName + "_foundEquivalentVersion", "1");
312  }
313  return newAssignedVersion;
314 } // end saveModifiedVersionXML()
315 
316 //==============================================================================
336  HttpXmlDocument& xmlOut,
337  ConfigurationManagerRW* cfgMgr,
338  const std::string& groupName,
339  const std::string& tableList,
340  bool allowDuplicates,
341  bool ignoreWarnings,
342  const std::string& groupComment,
343  bool lookForEquivalent)
344 try
345 {
346  __COUTT__ << "handleCreateTableGroupXML start runtime=" << cfgMgr->runTimeSeconds()
347  << __E__;
348 
349  xmlOut.addTextElementToData("AttemptedNewGroupName", groupName);
350 
351  // Only need table info for aliases and to check table names are valid
352  // ... so do not refresh, unless there is no info present.
353  std::string accumulatedWarnings;
354  const std::map<std::string, TableInfo>& allTableInfo =
355  cfgMgr->getAllTableInfo(); //no need to refresh
356  if(!allTableInfo.size()) //getAllTableInfo() will update allTableInfo by reference
357  cfgMgr->getAllTableInfo(true /* refresh */,
358  &accumulatedWarnings,
359  "" /* errorFilterName */,
360  true /* getGroupKeys*/,
361  false /* getGroupInfo */,
362  true /* initializeActiveGroups */);
363 
364  __COUT_WARN__ << "Ignoring these errors: " << accumulatedWarnings << __E__;
365  // cfgMgr->loadConfigurationBackbone(); //already loaded by initializeActiveGroups of getAllTableInfo
366 
367  __COUTT__ << "handleCreateTableGroupXML loaded runtime=" << cfgMgr->runTimeSeconds()
368  << __E__;
369 
370  std::map<std::string /*tableName*/,
371  std::map<std::string /*aliasName*/, TableVersion /*version*/>>
372  versionAliases = cfgMgr->getVersionAliases();
373  // for(const auto& aliases : versionAliases)
374  // for(const auto& alias : aliases.second)
375  // __COUT__ << aliases.first << " " << alias.first << " " << alias.second
376  // << __E__;
377 
378  std::map<std::string /*name*/, TableVersion /*version*/> groupMembers;
379  std::map<std::string /*name*/, std::string /*alias*/> memberTableAliases;
380 
381  std::string name, versionStr, alias;
382  TableVersion version;
383  auto c = tableList.find(',', 0);
384  auto i = c;
385  i = 0; // auto used to get proper index/length type
386  while(c < tableList.length())
387  {
388  // add the table and version pair to the map
389  name = tableList.substr(i, c - i);
390  i = c + 1;
391  c = tableList.find(',', i);
392  if(c == std::string::npos) // missing version list entry?!
393  {
394  __SS__ << "Incomplete Table Name-Version pair!" << __E__;
395  __COUT_ERR__ << "\n" << ss.str();
396  xmlOut.addTextElementToData("Error", ss.str());
397  return;
398  }
399 
400  versionStr = tableList.substr(i, c - i);
401  i = c + 1;
402  c = tableList.find(',', i);
403 
404  //__COUT__ << "name: " << name << __E__;
405  //__COUT__ << "versionStr: " << versionStr << __E__;
406 
407  // check if version is an alias and convert
408  if(versionStr.find(ConfigurationManager::ALIAS_VERSION_PREAMBLE) == 0)
409  {
410  alias =
411  versionStr.substr(ConfigurationManager::ALIAS_VERSION_PREAMBLE.size());
412 
413  __COUT__ << "Found alias " << name << " " << versionStr << __E__;
414 
415  // convert alias to version
416  if(versionAliases.find(name) != versionAliases.end() &&
417  versionAliases[name].find(alias) != versionAliases[name].end())
418  {
419  version = versionAliases[name][alias];
420  __COUT__ << name << " version alias '" << alias
421  << "'translated to: " << version << __E__;
422 
423  memberTableAliases[name] = alias;
424  }
425  else
426  {
427  __SS__ << "version alias '"
428  << versionStr.substr(
429  ConfigurationManager::ALIAS_VERSION_PREAMBLE.size())
430  << "' was not found in active version aliases! Please check your "
431  "active backbone!"
432  << __E__;
433  __COUT_ERR__ << "\n" << ss.str();
434  xmlOut.addTextElementToData("Error", ss.str());
435  return;
436  }
437  }
438  else
439  version = TableVersion(versionStr);
440 
441  if(version.isTemporaryVersion())
442  {
443  __SS__ << "Groups can not be created using temporary member tables. "
444  << "Table member '" << name << "' with temporary version '" << version
445  << "' is illegal." << __E__;
446  xmlOut.addTextElementToData("Error", ss.str());
447  return;
448  }
449 
450  // enforce that table exists
451  if(allTableInfo.find(name) == allTableInfo.end())
452  {
453  __SS__ << "Groups can not be created using mock-up member tables of "
454  "undefined tables. "
455  << "Table member '" << name << "' is not defined." << __E__;
456  xmlOut.addTextElementToData("Error", ss.str());
457  return;
458  }
459 
460  if(version.isMockupVersion())
461  {
462  // if mockup, then generate a new persistent version to use based on mockup
463  TableBase* table = cfgMgr->getTableByName(name);
464  // create a temporary version from the mockup as source version
465  TableVersion temporaryVersion = table->createTemporaryView();
466  __COUT__ << "\t\ttemporaryVersion: " << temporaryVersion << __E__;
467 
468  // if other versions exist check for another mockup, and use that instead
469  __COUT__ << "Creating version from mock-up for name: " << name
470  << " inputVersionStr: " << versionStr << __E__;
471 
472  // set table comment
473  table->getTemporaryView(temporaryVersion)
474  ->setComment("Auto-generated from mock-up.");
475 
476  // finish off the version creation
478  xmlOut,
479  cfgMgr,
480  name,
481  TableVersion() /*original source is mockup*/,
482  false /* makeTemporary */,
483  table,
484  temporaryVersion /*temporary modified version*/,
485  false /*ignore duplicates*/,
486  true /*look for equivalent*/);
487 
488  __COUT__ << "Using mockup version: " << version << __E__;
489  }
490 
491  //__COUT__ << "version: " << version << __E__;
492  groupMembers[name] = version;
493  } // end member verification loop
494 
495  __COUTT__ << "handleCreateTableGroupXML tables saved runtime="
496  << cfgMgr->runTimeSeconds() << __E__;
497 
498  __COUTV__(StringMacros::mapToString(memberTableAliases));
499 
500  if(!allowDuplicates)
501  {
502  __COUT__ << "Checking for duplicate groups..." << __E__;
503  try
504  {
505  TableGroupKey foundKey =
506  cfgMgr->findTableGroup(groupName, groupMembers, memberTableAliases);
507  __COUTT__ << "handleCreateTableGroupXML group duplicates checked runtime="
508  << cfgMgr->runTimeSeconds() << __E__;
509  if(!foundKey.isInvalid())
510  {
511  // return found equivalent key
512  xmlOut.addTextElementToData("TableGroupName", groupName);
513  xmlOut.addTextElementToData("TableGroupKey", foundKey.toString());
514 
515  if(lookForEquivalent)
516  {
517  __COUT__ << "Found equivalent group key (" << foundKey << ") for "
518  << groupName << "." << __E__;
519  // allow this equivalent group to be the response without an error
520  xmlOut.addTextElementToData("foundEquivalentKey", "1"); // indicator
521 
522  // insert get table info
523  handleGetTableGroupXML(xmlOut,
524  cfgMgr,
525  groupName,
526  foundKey,
527  ignoreWarnings,
528  true /* cacheOnly */);
529  return;
530  }
531  else // treat as error, if not looking for equivalent
532  {
533  __COUT__ << "Treating duplicate group as error." << __E__;
534  __SS__ << ("Failed to create table group: " + groupName +
535  ". It is a duplicate of an existing group key (" +
536  foundKey.toString() + ")");
537  __COUT_ERR__ << ss.str() << __E__;
538  xmlOut.addTextElementToData("Error", ss.str());
539  return;
540  }
541  }
542 
543  __COUT__ << "Check for duplicate groups complete." << __E__;
544  }
545  catch(...)
546  {
547  __COUT_WARN__ << "Ignoring errors looking for duplicate groups! Proceeding "
548  "with new group creation."
549  << __E__;
550  }
551  }
552 
553  // check the group for errors before creating group
554  try
555  {
556  cfgMgr->loadMemberMap(groupMembers);
557 
558  std::string accumulateErrors = "";
559  for(auto& groupMemberPair : groupMembers)
560  {
561  TableView* cfgViewPtr =
562  cfgMgr->getTableByName(groupMemberPair.first)->getViewP();
563  if(cfgViewPtr->getDataColumnSize() != cfgViewPtr->getNumberOfColumns() ||
564  cfgViewPtr->getSourceColumnMismatch() !=
565  0) // check for column size mismatch
566  {
567  // const std::set<std::string> srcColNames = cfgViewPtr->getSourceColumnNames();
568  __SS__ << "\n\nThere were errors found in loading a member table "
569  << groupMemberPair.first << ":v" << cfgViewPtr->getVersion()
570  << ". Please see the details below:\n\n"
571  << cfgViewPtr->getMismatchColumnInfo();
572 
573  __COUT_ERR__ << "\n" << ss.str();
574  xmlOut.addTextElementToData("Error", ss.str());
575  return;
576  }
577  }
578  }
579  catch(std::runtime_error& e)
580  {
581  __SS__ << "Failed to create table group: " << groupName
582  << ".\nThere were problems loading the chosen members:\n\n"
583  << e.what() << __E__;
584  __COUT_ERR__ << "\n" << ss.str();
585  xmlOut.addTextElementToData("Error", ss.str());
586  return;
587  }
588  catch(...)
589  {
590  __SS__ << "Failed to create table group: " << groupName << __E__;
591  try
592  {
593  throw;
594  } //one more try to printout extra info
595  catch(const std::exception& e)
596  {
597  ss << "Exception message: " << e.what();
598  }
599  catch(...)
600  {
601  }
602  __COUT_ERR__ << "\n" << ss.str();
603  xmlOut.addTextElementToData("Error", ss.str());
604  return;
605  }
606 
607  __COUTT__ << "handleCreateTableGroupXML group members init checked runtime="
608  << cfgMgr->runTimeSeconds() << __E__;
609 
610  // check the tree for warnings before creating group
611  std::string accumulateTreeErrs;
612  cfgMgr->getChildren(&groupMembers, &accumulateTreeErrs);
613  if(accumulateTreeErrs != "")
614  {
615  __COUT_WARN__ << "\n" << accumulateTreeErrs << __E__;
616  if(!ignoreWarnings)
617  {
618  xmlOut.addTextElementToData("TreeErrors", accumulateTreeErrs);
619  return;
620  }
621  }
622 
623  __COUTT__ << "handleCreateTableGroupXML tree checked runtime="
624  << cfgMgr->runTimeSeconds() << __E__;
625 
626  TableGroupKey newKey;
627  try
628  {
629  __COUT__ << "Saving new group..." << __E__;
630  newKey = cfgMgr->saveNewTableGroup(
631  groupName, groupMembers, groupComment, &memberTableAliases);
632  }
633  catch(std::runtime_error& e)
634  {
635  __SS__ << "Failed to create table group: " << groupName << __E__;
636  ss << "\n\n" << e.what() << __E__;
637  __COUT_ERR__ << ss.str();
638  xmlOut.addTextElementToData("Error", ss.str());
639  return;
640  }
641  catch(...)
642  {
643  __SS__ << "Failed to create table group: " << groupName << __E__;
644  try
645  {
646  throw;
647  } //one more try to printout extra info
648  catch(const std::exception& e)
649  {
650  ss << "Exception message: " << e.what();
651  }
652  catch(...)
653  {
654  }
655  __COUT_ERR__ << ss.str();
656  xmlOut.addTextElementToData("Error", ss.str());
657  return;
658  }
659 
660  __COUTT__ << "handleCreateTableGroupXML group saved runtime="
661  << cfgMgr->runTimeSeconds() << __E__;
662 
663  // insert get table info
664  __COUT__ << "Loading new table group..." << __E__;
666  xmlOut, cfgMgr, groupName, newKey, ignoreWarnings, true /* cacheOnly */);
667 
668  __COUTT__ << "handleCreateTableGroupXML end runtime=" << cfgMgr->runTimeSeconds()
669  << __E__;
670 
671 } // end handleCreateTableGroupXML()
672 catch(std::runtime_error& e)
673 {
674  __SS__ << "Error saving table group!\n\n " << e.what() << __E__;
675  __COUT_ERR__ << "\n" << ss.str() << __E__;
676  xmlOut.addTextElementToData("Error", ss.str());
677 }
678 catch(...)
679 {
680  __SS__ << "Error saving table group!" << __E__;
681  try
682  {
683  throw;
684  } //one more try to printout extra info
685  catch(const std::exception& e)
686  {
687  ss << "Exception message: " << e.what();
688  }
689  catch(...)
690  {
691  }
692  __COUT_ERR__ << "\n" << ss.str() << __E__;
693  xmlOut.addTextElementToData("Error", ss.str());
694 } // end handleCreateTableGroupXML() catch
695 
696 //==============================================================================
722  HttpXmlDocument& xmlOut,
723  ConfigurationManagerRW* cfgMgr,
724  const std::string& groupName,
725  TableGroupKey groupKey,
726  bool ignoreWarnings /* = false */,
727  bool cacheOnly /* = false */)
728 try
729 {
730  // char tmpIntStr[100];
731  xercesc::DOMElement *parentEl, *configEl;
732 
733  // steps:
734  // if invalid key, get latest key
735  // get specific group with key
736  // give member names and versions
737  // get all table groups to locate historical keys
738  // get all groups to find historical keys
739 
740  // std::set<std::string /*name+version*/> allGroups =
741  // cfgMgr->getConfigurationInterface()->getAllTableGroupNames(groupName);
742  // std::string name;
743  // TableGroupKey key;
744  // //put them in a set to sort them as TableGroupKey defines for operator<
745  // std::set<TableGroupKey> sortedKeys;
746  // for(auto& group: allGroups)
747  // {
748  // //now uses database filter
749  // TableGroupKey::getGroupNameAndKey(group,name,key);
750  // //if(name == groupName)
751  // sortedKeys.emplace(key);
752  // }
753 
754  __COUTTV__(cacheOnly);
755 
756  //======
758  auto SpanToXML = [](auto const& sortedKeys, auto& xmlOut) {
759  //add lo and hi spans, instead of each individual value
760  size_t lo = -1, hi = -1;
761  for(auto& keyInOrder : sortedKeys)
762  {
763  if(lo == size_t(-1)) //establish start of potential span
764  {
765  hi = lo = keyInOrder.key();
766  continue;
767  }
768  else if(hi + 1 == keyInOrder.key()) //span is growing
769  {
770  hi = keyInOrder.key();
771  continue;
772  }
773  //else jump by more than one, so close out span
774 
775  if(lo == hi) //single value
776  xmlOut.addNumberElementToData("HistoricalTableGroupKey", lo);
777  else //span
778  xmlOut.addTextElementToData(
779  "HistoricalTableGroupKey",
780  "_" + std::to_string(lo) + "_" + std::to_string(hi));
781  hi = lo = keyInOrder.key();
782  }
783 
784  if(lo != size_t(-1)) //check if last one to do!
785  {
786  if(lo == hi) //single value
787  xmlOut.addNumberElementToData("HistoricalTableGroupKey", lo);
788  else //span
789  xmlOut.addTextElementToData(
790  "HistoricalTableGroupKey",
791  "_" + std::to_string(lo) + "_" + std::to_string(hi));
792  }
793  }; //end local lambda SpanToXML()
794  auto vSpanToXML = [](auto const& sortedKeys, auto& xmlOut, auto& configEl) {
795  //add lo and hi spans, instead of each individual value
796  size_t lo = -1, hi = -1;
797  for(auto& keyInOrder : sortedKeys)
798  {
799  if(lo == size_t(-1)) //establish start of potential span
800  {
801  hi = lo = keyInOrder.version();
802  continue;
803  }
804  else if(hi + 1 == keyInOrder.version()) //span is growing
805  {
806  hi = keyInOrder.version();
807  continue;
808  }
809  //else jump by more than one, so close out span
810 
811  if(lo == hi) //single value
812  xmlOut.addNumberElementToParent("TableExistingVersion", lo, configEl);
813  else //span
814  xmlOut.addTextElementToParent(
815  "TableExistingVersion",
816  "_" + std::to_string(lo) + "_" + std::to_string(hi),
817  configEl);
818  hi = lo = keyInOrder.version();
819  }
820 
821  if(lo != size_t(-1)) //check if last one to do!
822  {
823  if(lo == hi) //single value
824  xmlOut.addNumberElementToParent("TableExistingVersion", lo, configEl);
825  else //span
826  xmlOut.addTextElementToParent(
827  "TableExistingVersion",
828  "_" + std::to_string(lo) + "_" + std::to_string(hi),
829  configEl);
830  }
831  }; //end local lambda vSpanToXML()
832 
833  {
834  const GroupInfo& groupInfo =
835  cfgMgr->getGroupInfo(groupName, !cacheOnly /* attemptToReloadKeys */);
836  const std::set<TableGroupKey>& sortedKeys = groupInfo.getKeys(); // rename
837 
838  __COUTT__ << groupName << " keys: " << StringMacros::setToString(sortedKeys)
839  << __E__;
840  __COUTT__ << "Active groups: "
841  << StringMacros::mapToString(cfgMgr->getActiveTableGroups()) << __E__;
842  __COUTT__ << "Active tables: "
843  << StringMacros::mapToString(cfgMgr->getActiveVersions()) << __E__;
844 
845  if(!cacheOnly &&
846  (groupKey
847  .isInvalid() || // if invalid or not found, likely key info not loaded, so get latest
848  sortedKeys.find(groupKey) == sortedKeys.end() ||
849  sortedKeys.size() < 2))
850  {
851  // report error if group key not found
852  if(!groupKey.isInvalid() || sortedKeys.size() == 0)
853  {
854  // attempt to reload all group info and power through
855  std::string accumulatedWarnings;
856  __COUTT__ << "Attempting full table refresh (assuming cache not yet "
857  "established)."
858  << __E__;
859  /*const std::map<std::string, TableInfo>& allTableInfo = */ cfgMgr
860  ->getAllTableInfo(true /* refresh */,
861  &accumulatedWarnings,
862  "" /* errorFilterName */,
863  true /* getGroupKeys*/,
864  false /* getGroupInfo */,
865  true /* initializeActiveGroups */);
866  __COUTT__ << "After full table refresh (assuming cache not yet "
867  "established) so ignoring these errors: "
868  << accumulatedWarnings << __E__;
869 
870  // xmlOut.addTextElementToData("Error", ss.str());
871 
872  const GroupInfo& groupInfo2 = cfgMgr->getGroupInfo(groupName);
873  const std::set<TableGroupKey>& sortedKeys2 =
874  groupInfo2.getKeys(); // rename
875 
876  if(sortedKeys2.find(groupKey) == sortedKeys2.end())
877  {
878  __SS__ << "Group key " << groupKey << " was not found for group '"
879  << groupName << "!'" << __E__;
880  ss << "Her are the found " << sortedKeys2.size() << " '" << groupName
881  << "' keys: " << __E__;
882  for(auto& keyInOrder : sortedKeys2)
883  ss << "\t" << keyInOrder << __E__;
884  __COUT_WARN__ << "\n" << ss.str() << __E__;
885  }
886  SpanToXML(sortedKeys2, xmlOut);
887  }
888  else
889  {
890  if(sortedKeys.size())
891  groupKey = *sortedKeys.rbegin();
892  __COUT_WARN__
893  << "Group key requested was invalid or not found, going with latest "
894  << groupKey << __E__;
895 
896  // add all other sorted keys for this groupName
897  SpanToXML(sortedKeys, xmlOut);
898  }
899  }
900  else
901  {
902  // add all other sorted keys for this groupName
903  SpanToXML(sortedKeys, xmlOut);
904  }
905 
906  if(cfgMgr->getActiveVersions().size() == 0)
907  {
908  __COUTT__
909  << "There are no active tables. Attempting to initialize active groups."
910  << __E__;
911  //if no active tables, attempt to init active groups (it should prevent confusing warnings to users complaining about a partially loaded configuration)
912  std::string tmpAccumulateWarnings;
913  cfgMgr->init(0 /*accumulatedErrors*/,
914  false /*initForWriteAccess*/,
915  &tmpAccumulateWarnings);
916  __COUTT__ << "Now Active tables: "
917  << StringMacros::mapToString(cfgMgr->getActiveVersions()) << __E__;
918  __COUTT__ << "Ingoring warnings during init of active groups: "
919  << tmpAccumulateWarnings << __E__;
920  }
921  }
922 
923  xmlOut.addTextElementToData("TableGroupName", groupName);
924  xmlOut.addTextElementToData("TableGroupKey", groupKey.toString());
925 
926  parentEl = xmlOut.addTextElementToData("TableGroupMembers", "");
927 
928  // get specific group with key
929  std::map<std::string /*name*/, TableVersion /*version*/> memberMap;
930  std::map<std::string /*name*/, std::string /*alias*/> groupMemberAliases;
931 
932  __COUT__ << "groupName=" << groupName << __E__;
933  __COUT__ << "groupKey=" << groupKey << __E__;
934 
935  const std::map<std::string, TableInfo>& allTableInfo = cfgMgr->getAllTableInfo();
936  std::map<std::string, TableInfo>::const_iterator it;
937 
938  // load group so comments can be had
939  // and also group metadata (author, comment, createTime)
940  try
941  {
942  std::string groupAuthor, groupComment, groupCreationTime, groupTypeString;
943  std::string accumulateTreeErrors;
944 
945  __COUTV__(ignoreWarnings);
946  cfgMgr->loadTableGroup(groupName,
947  groupKey,
948  false /*doActivate*/,
949  &memberMap,
950  0 /*progressBar*/,
951  ignoreWarnings ? 0 : /*accumulateTreeErrors*/
952  &accumulateTreeErrors,
953  &groupComment,
954  &groupAuthor,
955  &groupCreationTime,
956  false /*doNotLoadMember*/,
957  &groupTypeString,
958  &groupMemberAliases);
959 
960  if(accumulateTreeErrors != "")
961  {
962  __COUTV__(accumulateTreeErrors);
963  xmlOut.addTextElementToData("TreeErrors", accumulateTreeErrors);
964  }
965 
966  xmlOut.addTextElementToData("TableGroupAuthor", groupAuthor);
967  xmlOut.addTextElementToData("TableGroupComment", groupComment);
968  xmlOut.addTextElementToData("TableGroupCreationTime", groupCreationTime);
969  xmlOut.addTextElementToData("TableGroupType", groupTypeString);
970  }
971  catch(const std::runtime_error& e)
972  {
973  __SS__ << "Table group \"" + groupName + "(" + groupKey.toString() + ")" +
974  "\" members can not be loaded!\n\n" + e.what()
975  << __E__;
976  __COUT_ERR__ << ss.str();
977  xmlOut.addTextElementToData("Error", ss.str());
978  // return;
979  }
980  catch(...)
981  {
982  __SS__ << "Table group \"" + groupName + "(" + groupKey.toString() + ")" +
983  "\" members can not be loaded!"
984  << __E__;
985  try
986  {
987  throw;
988  } //one more try to printout extra info
989  catch(const std::exception& e)
990  {
991  ss << "Exception message: " << e.what();
992  }
993  catch(...)
994  {
995  }
996  __COUT_ERR__ << ss.str();
997  xmlOut.addTextElementToData("Error", ss.str());
998  // return;
999  }
1000 
1001  __COUTV__(StringMacros::mapToString(groupMemberAliases));
1002 
1003  std::map<std::string, std::map<std::string, TableVersion>> versionAliases =
1004  cfgMgr->getVersionAliases();
1005 
1006  __COUT__ << "# of table version aliases: " << versionAliases.size() << __E__;
1007 
1008  // Seperate loop to get name and version
1009  for(auto& memberPair : memberMap)
1010  {
1011  xmlOut.addTextElementToParent("MemberName", memberPair.first, parentEl);
1012 
1013  // if member is in groupMemberAliases, then alias version
1014  if(groupMemberAliases.find(memberPair.first) != groupMemberAliases.end())
1015  configEl = xmlOut.addTextElementToParent(
1016  "MemberVersion",
1017  ConfigurationManager::ALIAS_VERSION_PREAMBLE +
1018  groupMemberAliases[memberPair.first], // return the ALIAS:<alias>
1019  parentEl);
1020  else
1021  configEl = xmlOut.addTextElementToParent(
1022  "MemberVersion", memberPair.second.toString(), parentEl);
1023 
1024  it = allTableInfo.find(memberPair.first);
1025  if(it == allTableInfo.end())
1026  {
1027  if(!cacheOnly) //only an 'error' if not cacheOnly
1028  xmlOut.addTextElementToData(
1029  "Error", "Table \"" + memberPair.first + "\" can not be retrieved!");
1030  continue;
1031  }
1032 
1033  xmlOut.addTextElementToParent(
1034  "MemberComment", it->second.tablePtr_->getView().getComment(), parentEl);
1035 
1036  if(versionAliases.find(it->first) != versionAliases.end())
1037  for(auto& aliasVersion : versionAliases[it->first])
1038  xmlOut.addTextElementToParent(
1039  "TableExistingVersion",
1040  ConfigurationManager::ALIAS_VERSION_PREAMBLE + aliasVersion.first,
1041  configEl);
1042 
1043  vSpanToXML(it->second.versions_, xmlOut, configEl);
1044  } //end member map loop
1045 
1046  // // Seperate loop just for getting the Member Comment
1047  // for(auto& memberPair : memberMap)
1048  // {
1049  // //__COUT__ << "\tMember table " << memberPair.first << ":" <<
1050  // // memberPair.second << __E__;
1051 
1052  // // xmlOut.addTextElementToParent("MemberName", memberPair.first, parentEl);
1053  // // if(commentsLoaded)
1054  // xmlOut.addTextElementToParent(
1055  // "MemberComment",
1056  // allTableInfo.at(memberPair.first).tablePtr_->getView().getComment(),
1057  // parentEl);
1058  // // else
1059  // // xmlOut.addTextElementToParent("MemberComment", "", parentEl);
1060 
1061  // // __COUT__ << "\tMember table " << memberPair.first << ":" <<
1062  // // memberPair.second << __E__;
1063 
1064  // // configEl = xmlOut.addTextElementToParent("MemberVersion",
1065  // // memberPair.second.toString(), parentEl);
1066 
1067  // /* it = allTableInfo.find(memberPair.first);
1068  // if(it == allTableInfo.end())
1069  // {
1070  // xmlOut.addTextElementToData("Error","Table \"" +
1071  // memberPair.first +
1072  // "\" can not be retrieved!");
1073  // return;
1074  // }
1075  // */
1076  // // include aliases for this table
1077  // /*if(versionAliases.find(it->first) != versionAliases.end())
1078  // for (auto& aliasVersion:versionAliases[it->first])
1079  // xmlOut.addTextElementToParent("TableExistingVersion",
1080  // ConfigurationManager::ALIAS_VERSION_PREAMBLE + aliasVersion.first,
1081  // configEl);
1082 
1083  // for (auto& version:it->second.versions_)
1084  // //if(version == memberPair.second) continue; //CHANGED by RAR on 11/14/2016
1085  // (might as well show all versions in list to avoid user confusion)
1086  // //else
1087  // xmlOut.addTextElementToParent("TableExistingVersion",
1088  // version.toString(), configEl);
1089  // */
1090  // }
1091 
1092 } // end handleGetTableGroupXML()
1093 catch(std::runtime_error& e)
1094 {
1095  __SS__ << ("Error getting table group!\n\n" + std::string(e.what())) << __E__;
1096  __COUT_ERR__ << "\n" << ss.str();
1097  xmlOut.addTextElementToData("Error", ss.str());
1098 }
1099 catch(...)
1100 {
1101  __SS__ << ("Error getting table group!\n\n") << __E__;
1102  try
1103  {
1104  throw;
1105  } //one more try to printout extra info
1106  catch(const std::exception& e)
1107  {
1108  ss << "Exception message: " << e.what();
1109  }
1110  catch(...)
1111  {
1112  }
1113  __COUT_ERR__ << "\n" << ss.str();
1114  xmlOut.addTextElementToData("Error", ss.str());
1115 } // end handleGetTableGroupXML() catch
1116 
1117 //==============================================================================
1118 bool ConfigurationSupervisorBase::handleAddDesktopIconXML(
1119  HttpXmlDocument& xmlOut,
1120  ConfigurationManagerRW* cfgMgr,
1121  const std::string& iconCaption,
1122  const std::string& iconAltText,
1123  const std::string& iconFolderPath,
1124  const std::string& iconImageURL,
1125  const std::string& iconWindowURL,
1126  const std::string& iconPermissions,
1127  std::string windowLinkedApp /*= ""*/,
1128  unsigned int windowLinkedAppLID /*= 0*/,
1129  bool enforceOneWindowInstance /*= false*/,
1130  const std::string& windowParameters /*= ""*/)
1131 try
1132 {
1133  cfgMgr->getAllTableInfo(true /* refresh */);
1134 
1135  const std::string& author = cfgMgr->getUsername();
1136 
1137  __COUTV__(author);
1138  __COUTV__(iconCaption);
1139  __COUTV__(iconAltText);
1140  __COUTV__(iconFolderPath);
1141  __COUTV__(iconImageURL);
1142  __COUTV__(iconWindowURL);
1143  __COUTV__(iconPermissions);
1144  __COUTV__(windowLinkedApp);
1145  __COUTV__(windowLinkedAppLID);
1146  __COUTV__(enforceOneWindowInstance);
1147 
1148  __COUTV__(windowParameters); // map: CSV list
1149 
1150  // steps:
1151  // activate active context
1152  // modify desktop table and desktop parameters table
1153  // save, activate, and modify alias
1154  // just to match syntax in ConfiguratGUI
1155  // tmpCfgMgr.activateTableGroup(
1156  // tmpCfgMgr.getActiveGroupName(ConfigurationManager::GROUP_TYPE_NAME_CONTEXT),
1157  // tmpCfgMgr.getActiveGroupKey(ConfigurationManager::GROUP_TYPE_NAME_CONTEXT)
1158  // );
1159 
1160  cfgMgr->restoreActiveTableGroups(
1161  true /*throwErrors*/,
1162  "" /*pathToActiveGroupsFile*/,
1163  ConfigurationManager::LoadGroupType::
1164  ONLY_BACKBONE_OR_CONTEXT_TYPES /*onlyLoadIfBackboneOrContext*/
1165  );
1166 
1167  const std::string backboneGroupName =
1168  cfgMgr->getActiveGroupName(ConfigurationManager::GroupType::BACKBONE_TYPE);
1169 
1170  GroupEditStruct contextGroupEdit(ConfigurationManager::GroupType::CONTEXT_TYPE,
1171  cfgMgr);
1172 
1173  // Steps:
1174  // - Create record in DesktopIconTable
1175  // - Create parameter records in DesktopWindowParameterTable
1176  // - Create new Context group
1177  // - Update Aliases from old Context group to new Context group
1178  // - Activate new group
1179 
1180  TableEditStruct& iconTable = contextGroupEdit.getTableEditStruct(
1181  DesktopIconTable::ICON_TABLE, true /*markModified*/);
1182  TableEditStruct& parameterTable = contextGroupEdit.getTableEditStruct(
1183  DesktopIconTable::PARAMETER_TABLE, true /*markModified*/);
1184  TableEditStruct& appTable = contextGroupEdit.getTableEditStruct(
1185  ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME);
1186 
1187  // Create record in DesktopIconTable
1188  try
1189  {
1190  unsigned int row;
1191  std::string iconUID = "";
1192  std::string decodedCaption = StringMacros::decodeURIComponent(iconCaption);
1193 
1194  for(unsigned int i = 0; i < decodedCaption.size(); ++i)
1195  if((decodedCaption[i] >= 'a' && decodedCaption[i] <= 'z') ||
1196  (decodedCaption[i] >= 'A' && decodedCaption[i] <= 'Z') ||
1197  (decodedCaption[i] >= '0' && decodedCaption[i] <= '9'))
1198  iconUID += decodedCaption[i];
1199 
1200  // create icon record
1201  row = iconTable.tableView_->addRow(
1202  author, true /*incrementUniqueData*/, "generatedIcon" + iconUID);
1203  iconUID =
1204  iconTable.tableView_->getDataView()[row][iconTable.tableView_->getColUID()];
1205 
1206  __COUTV__(row);
1207  __COUTV__(iconUID);
1208 
1209  // set icon status true
1210  iconTable.tableView_->setValueAsString(
1211  "1", row, iconTable.tableView_->getColStatus());
1212 
1213  // set caption value
1214  iconTable.tableView_->setURIEncodedValue(
1215  iconCaption,
1216  row,
1217  iconTable.tableView_->findCol(DesktopIconTable::COL_CAPTION));
1218  // set alt text value
1219  iconTable.tableView_->setURIEncodedValue(
1220  iconAltText,
1221  row,
1222  iconTable.tableView_->findCol(DesktopIconTable::COL_ALTERNATE_TEXT));
1223  // set force one instance value
1224  iconTable.tableView_->setValueAsString(
1225  enforceOneWindowInstance ? "1" : "0",
1226  row,
1227  iconTable.tableView_->findCol(DesktopIconTable::COL_FORCE_ONLY_ONE_INSTANCE));
1228  // set permissions value
1229  iconTable.tableView_->setURIEncodedValue(
1230  iconPermissions,
1231  row,
1232  iconTable.tableView_->findCol(DesktopIconTable::COL_PERMISSIONS));
1233  // set image URL value
1234  iconTable.tableView_->setURIEncodedValue(
1235  iconImageURL,
1236  row,
1237  iconTable.tableView_->findCol(DesktopIconTable::COL_IMAGE_URL));
1238  // set window URL value
1239  iconTable.tableView_->setURIEncodedValue(
1240  iconWindowURL,
1241  row,
1242  iconTable.tableView_->findCol(DesktopIconTable::COL_WINDOW_CONTENT_URL));
1243  // set folder value
1244  iconTable.tableView_->setURIEncodedValue(
1245  iconFolderPath,
1246  row,
1247  iconTable.tableView_->findCol(DesktopIconTable::COL_FOLDER_PATH));
1248 
1249  // create link to icon app
1250  if(windowLinkedAppLID > 0)
1251  {
1252  __COUTV__(windowLinkedAppLID);
1253 
1254  int appRow = appTable.tableView_->findRow(
1255  appTable.tableView_->findCol(XDAQContextTable::colApplication_.colId_),
1256  windowLinkedAppLID);
1257  windowLinkedApp =
1258  appTable.tableView_
1259  ->getDataView()[appRow][appTable.tableView_->getColUID()];
1260  __COUT__ << "Found app by LID: " << windowLinkedApp << __E__;
1261  } // end linked app LID handling
1262 
1263  if(windowLinkedApp != "" && windowLinkedApp != "undefined" &&
1264  windowLinkedApp != TableViewColumnInfo::DATATYPE_STRING_DEFAULT)
1265  {
1266  // first check that UID exists
1267  // if not, interpret as app class type and
1268  // check for unique 'enabled' app with class type
1269  __COUTV__(windowLinkedApp);
1270 
1271  if(!windowLinkedAppLID) // no need to check if LID lookup happened already
1272  {
1273  try
1274  {
1275  windowLinkedApp = StringMacros::decodeURIComponent(windowLinkedApp);
1276  /* int appRow = */ appTable.tableView_->findRow(
1277  appTable.tableView_->getColUID(), windowLinkedApp);
1278  }
1279  catch(const std::runtime_error& e)
1280  {
1281  // attempt to treat like class, and take first match
1282  try
1283  {
1284  int appRow = appTable.tableView_->findRow(
1285  appTable.tableView_->findCol(
1286  XDAQContextTable::colApplication_.colClass_),
1287  windowLinkedApp);
1288  windowLinkedApp =
1289  appTable.tableView_
1290  ->getDataView()[appRow][appTable.tableView_->getColUID()];
1291  }
1292  catch(...)
1293  {
1294  // failed to treat like class, so throw original
1295  __SS__
1296  << "Failed to create an icon linking to XDAQ Supervisor app '"
1297  << windowLinkedApp
1298  << ".' Please make sure the Supervisor exists in the "
1299  << ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME
1300  << " table. "
1301  << "\n\nThe following error occurred: " << e.what() << __E__;
1302  appTable.tableView_->print(ss);
1303  __SS_THROW__;
1304  }
1305  }
1306  }
1307  __COUTV__(windowLinkedApp);
1308 
1309  iconTable.tableView_->setValueAsString(
1310  ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME,
1311  row,
1312  iconTable.tableView_->findCol(DesktopIconTable::COL_APP_LINK));
1313  iconTable.tableView_->setValueAsString(
1314  windowLinkedApp,
1315  row,
1316  iconTable.tableView_->findCol(DesktopIconTable::COL_APP_LINK_UID));
1317  } // end create app link
1318 
1319  // parse parameters
1320  std::map<std::string, std::string> parameters;
1321 
1322  __COUTV__(windowParameters);
1323  StringMacros::getMapFromString(windowParameters, parameters);
1324 
1325  // create link to icon parameters
1326  if(parameters.size())
1327  {
1328  // set parameter link table
1329  iconTable.tableView_->setValueAsString(
1330  DesktopIconTable::PARAMETER_TABLE,
1331  row,
1332  iconTable.tableView_->findCol(DesktopIconTable::COL_PARAMETER_LINK));
1333  // set parameter link Group ID
1334  iconTable.tableView_->setValueAsString(
1335  iconUID + "_Parameters",
1336  row,
1337  iconTable.tableView_->findCol(DesktopIconTable::COL_PARAMETER_LINK_GID));
1338 
1339  __COUTV__(StringMacros::mapToString(parameters));
1340 
1341  unsigned int gidCol =
1342  parameterTable.tableView_->findCol(DesktopIconTable::COL_PARAMETER_GID);
1343 
1344  // remove all existing records from groupID (e.g. parameters leftover from manual manipulations)
1345  std::vector<unsigned int /*row*/> rowsInGroup =
1346  parameterTable.tableView_->getGroupRows(
1347  gidCol, iconUID + "_Parameters" /*groupID*/);
1348 
1349  __COUTV__(StringMacros::vectorToString(rowsInGroup));
1350 
1351  // go through vector backwards to maintain row integrity
1352  for(unsigned int r = rowsInGroup.size() - 1; r < rowsInGroup.size(); --r)
1353  parameterTable.tableView_->removeRowFromGroup(
1354  rowsInGroup[r],
1355  gidCol,
1356  iconUID + "_Parameters" /*groupID*/,
1357  true /*deleteRowIfNoGroupLeft*/);
1358 
1359  // create new parameters
1360  for(const auto& parameter : parameters)
1361  {
1362  // create parameter record
1363  row = parameterTable.tableView_->addRow(
1364  author, true /*incrementUniqueData*/, "generatedParameter");
1365 
1366  // set parameter status true
1367  parameterTable.tableView_->setValueAsString(
1368  "1", row, parameterTable.tableView_->getColStatus());
1369  // set parameter Group ID
1370  parameterTable.tableView_->setValueAsString(
1371  iconUID + "_Parameters", row, gidCol);
1372  // set parameter key
1373  parameterTable.tableView_->setURIEncodedValue(
1374  parameter.first,
1375  row,
1376  parameterTable.tableView_->findCol(
1377  DesktopIconTable::COL_PARAMETER_KEY));
1378  // set parameter value
1379  parameterTable.tableView_->setURIEncodedValue(
1380  parameter.second,
1381  row,
1382  parameterTable.tableView_->findCol(
1383  DesktopIconTable::COL_PARAMETER_VALUE));
1384  } // end parameter loop
1385 
1386  std::stringstream ss;
1387  parameterTable.tableView_->print(ss);
1388  __COUT__ << ss.str();
1389 
1390  parameterTable.tableView_
1391  ->init(); // verify new table (throws runtime_errors)
1392 
1393  } // end create parameters link
1394 
1395  std::stringstream ss;
1396  iconTable.tableView_->print(ss);
1397  __COUT__ << ss.str();
1398 
1399  iconTable.tableView_->init(); // verify new table (throws runtime_errors)
1400  }
1401  catch(...)
1402  {
1403  __COUT__ << "Icon table errors while saving. Erasing all newly "
1404  "created table versions."
1405  << __E__;
1406 
1407  throw; // re-throw
1408  } // end catch
1409 
1410  __COUT__ << "Edits complete for new desktop icon, now making persistent tables."
1411  << __E__;
1412 
1413  // all edits are complete and tables verified
1414 
1415  // Remaining steps:
1416  // save tables
1417  // save new context group and activate it
1418  // check for aliases ...
1419  // if tables aliased.. update table aliases in backbone
1420  // if context group aliased, update group aliases in backbone
1421  // if backbone modified, save group and activate it
1422 
1423  TableGroupKey newContextKey;
1424  bool foundEquivalentContextKey;
1425  TableGroupKey newBackboneKey;
1426  bool foundEquivalentBackboneKey;
1427 
1428  contextGroupEdit.saveChanges(contextGroupEdit.originalGroupName_,
1429  newContextKey,
1430  &foundEquivalentContextKey,
1431  true /*activateNewGroup*/,
1432  true /*updateGroupAliases*/,
1433  true /*updateTableAliases*/,
1434  &newBackboneKey,
1435  &foundEquivalentBackboneKey);
1436 
1437  xmlOut.addTextElementToData("contextGroupName", contextGroupEdit.originalGroupName_);
1438  xmlOut.addTextElementToData("contextGroupKey", newContextKey.toString());
1439 
1440  xmlOut.addTextElementToData("backboneGroupName", backboneGroupName);
1441  xmlOut.addTextElementToData("backboneGroupKey", newBackboneKey.toString());
1442 
1443  // always add active table groups to xml response
1445 
1446  return true;
1447 } // end handleAddDesktopIconXML()
1448 catch(std::runtime_error& e)
1449 {
1450  __SS__ << "Error adding Desktop Icon!\n\n " << e.what() << __E__;
1451  __COUT__ << "\n" << ss.str() << __E__;
1452  xmlOut.addTextElementToData("Error", ss.str());
1453  return false;
1454 }
1455 catch(...)
1456 {
1457  __SS__ << "Error adding Desktop Icon!" << __E__;
1458  try
1459  {
1460  throw;
1461  } //one more try to printout extra info
1462  catch(const std::exception& e)
1463  {
1464  ss << "Exception message: " << e.what();
1465  }
1466  catch(...)
1467  {
1468  }
1469  __COUT__ << "\n" << ss.str() << __E__;
1470  xmlOut.addTextElementToData("Error", ss.str());
1471  return false;
1472 } // end handleAddDesktopIconXML() catch
1473 
1474 //==============================================================================
1475 void ConfigurationSupervisorBase::recursiveCopyTreeUIDNode(
1476  HttpXmlDocument& xmlOut,
1477  ConfigurationManagerRW* cfgMgr,
1478  std::map<std::string /*modified table*/, TableVersion /* modified version */>&
1479  modifiedTablesMap,
1480  const unsigned int startingDepth,
1481  const unsigned int depth,
1482  const unsigned int numberOfInstances,
1483  TableView* cfgView,
1484  const std::string& uidToCopy)
1485 try
1486 {
1487  __COUTV__(startingDepth);
1488  __COUTV__(depth);
1489  __COUTV__(numberOfInstances);
1490 
1491  // throw std::runtime_error("hello");
1492 
1493  // Steps:
1494  // Assume temporary table version already created correctly for recursive level
1495  // Assume already decided it is correct to copy record at row parameter
1496  // Assume after modifications the version saving is handled above this function call
1497  // 1. copy the target row
1498  // - if depth,
1499  // 2. - check source row, for secondary copies through links
1500  // - if a link is found, check that there is not unanimous pointing by siblings
1501  // -- if unanimous pointing by siblings, do not do secondary copy, just point
1502  // 3. -- if not unanimous,
1503  // * use/create temporary version of child table
1504  // * for each instance
1505  // - recursive secondary copy (depth-1)
1506  // * save child table
1507  //
1508 
1509  // Step 1. copy the target row
1510  unsigned int col = cfgView->getColUID();
1511  unsigned int row = cfgView->findRow(col, uidToCopy);
1512 
1513  __COUT__ << "Copying " << cfgView->getTableName() << " v" << cfgView->getVersion()
1514  << " row=" << row << " record=" << uidToCopy
1515  << " instances=" << numberOfInstances << __E__;
1516 
1517  cfgView->print();
1518  // for(unsigned int i = 0; i < numberOfInstances; ++i)
1519  cfgView->copyRows(cfgMgr->getUsername(),
1520  *cfgView /*source table*/,
1521  row,
1522  1 /*srcRowsToCopy*/,
1523  -1 /*destOffsetRow*/,
1524  true /*generateUniqueDataColumns*/,
1525  uidToCopy /*baseNameAutoUID*/); // make the name similar
1526 
1527  // if no secondary copies, done now
1528  // check for secondary copies
1529  return;
1530 
1531  // secondary table copies
1532  std::string tableName = "secondary";
1533  TableVersion version(modifiedTablesMap.at(tableName));
1534 
1535  TableBase* table = cfgMgr->getTableByName(tableName);
1536  try
1537  {
1538  table->setActiveView(version);
1539  }
1540  catch(...)
1541  {
1542  if(version.isTemporaryVersion())
1543  throw; // if temporary, there is no hope to find lost version
1544 
1545  __COUT__ << "Failed to find stored version, so attempting to "
1546  "load version: "
1547  << tableName << " v" << version << __E__;
1548  cfgMgr->getVersionedTableByName(tableName, version);
1549  }
1550 
1551  __COUT__ << tableName << " active version is " << table->getViewVersion() << __E__;
1552 
1553  if(version != table->getViewVersion())
1554  {
1555  __SS__ << "Target table version (" << version
1556  << ") is not the currently active version (" << table->getViewVersion()
1557  << "). Try refreshing the tree." << __E__;
1558  __SS_THROW__;
1559  }
1560 
1561  // version handling:
1562  // always make a new temporary-version from source-version
1563  // edit temporary-version
1564  // if edit fails
1565  // delete temporary-version
1566  // else
1567  // return new temporary-version
1568  // if source-version was temporary
1569  // then delete source-version
1570  TableVersion temporaryVersion = table->createTemporaryView(version);
1571 
1572  __COUT__ << "Created temporary version " << temporaryVersion << __E__;
1573 
1574  cfgView = table->getTemporaryView(temporaryVersion);
1575  cfgView->init(); // prepare maps
1576 
1577  try // while editing
1578  {
1579  // edit...
1580 
1581  cfgView->init(); // verify new table (throws runtime_errors)
1582  }
1583  catch(...) // erase temporary view before re-throwing error
1584  {
1585  __COUT__ << "Caught error while editing. Erasing temporary version." << __E__;
1586  table->eraseView(temporaryVersion);
1587  throw;
1588  }
1589 
1591  xmlOut,
1592  cfgMgr,
1593  tableName,
1594  version,
1595  true /*make temporary*/,
1596  table,
1597  temporaryVersion,
1598  true /*ignoreDuplicates*/); // save temporary version properly
1599 }
1600 catch(std::runtime_error& e)
1601 {
1602  __SS__ << ("Error copying tree target '" + uidToCopy + "' at depth " +
1603  std::to_string(startingDepth - depth) + " in table '" +
1604  cfgView->getTableName() + ".' " + std::string(e.what()))
1605  << __E__;
1606  __COUT__ << "\n" << ss.str() << __E__;
1607  xmlOut.addTextElementToData("Error", ss.str());
1608 }
1609 catch(...)
1610 {
1611  __SS__ << ("Error copying tree target '" + uidToCopy + "' at depth " +
1612  std::to_string(startingDepth - depth) + " in table '" +
1613  cfgView->getTableName() + ".' ")
1614  << __E__;
1615  try
1616  {
1617  throw;
1618  } //one more try to printout extra info
1619  catch(const std::exception& e)
1620  {
1621  ss << "Exception message: " << e.what();
1622  }
1623  catch(...)
1624  {
1625  }
1626  __COUT__ << "\n" << ss.str() << __E__;
1627  xmlOut.addTextElementToData("Error", ss.str());
1628 } // end recursiveCopyTreeUIDNode
TableGroupKey findTableGroup(const std::string &groupName, const std::map< std::string, TableVersion > &groupMembers, const std::map< std::string, std::string > &groupAliases=std::map< std::string, std::string >())
const GroupInfo & getGroupInfo(const std::string &groupName, bool attemptToReloadKeys=false)
public group cache handling
const std::map< std::string, TableInfo > & getAllTableInfo(bool refresh=false, std::string *accumulatedWarnings=0, const std::string &errorFilterName="", bool getGroupKeys=false, bool getGroupInfo=false, bool initializeActiveGroups=false)
void loadTableGroup(const std::string &tableGroupName, const TableGroupKey &tableGroupKey, bool doActivate=false, std::map< std::string, TableVersion > *groupMembers=0, ProgressBar *progressBar=0, std::string *accumulateWarnings=0, std::string *groupComment=0, std::string *groupAuthor=0, std::string *groupCreateTime=0, bool doNotLoadMember=false, std::string *groupTypeString=0, std::map< std::string, std::string > *groupAliases=0, ConfigurationManager::LoadGroupType groupTypeToLoad=ConfigurationManager::LoadGroupType::ALL_TYPES, bool ignoreVersionTracking=false)
TableGroupKey saveNewTableGroup(const std::string &groupName, std::map< std::string, TableVersion > &groupMembers, const std::string &groupComment=TableViewColumnInfo::DATATYPE_COMMENT_DEFAULT, std::map< std::string, std::string > *groupAliases=0)
modifiers of a table group based on alias, e.g. "Physics"
TableVersion saveModifiedVersion(const std::string &tableName, TableVersion originalVersion, bool makeTemporary, TableBase *config, TableVersion temporaryModifiedVersion, bool ignoreDuplicates=false, bool lookForEquivalent=false, bool *foundEquivalent=nullptr)
const std::string & getUsername(void) const
Getters.
std::map< std::string, std::map< std::string, TableVersion > > getVersionAliases(void) const
TableBase * getVersionedTableByName(const std::string &tableName, TableVersion version, bool looseColumnMatching=false, std::string *accumulatedErrors=0, bool getRawData=false)
void restoreActiveTableGroups(bool throwErrors=false, const std::string &pathToActiveGroupsFile="", ConfigurationManager::LoadGroupType onlyLoadIfBackboneOrContext=ConfigurationManager::LoadGroupType::ALL_TYPES, std::string *accumulatedWarnings=0)
std::map< std::string, std::pair< std::string, TableGroupKey > > getActiveTableGroups(void) const
void loadMemberMap(const std::map< std::string, TableVersion > &memberMap, std::string *accumulateWarnings=0)
std::map< std::string, TableVersion > getActiveVersions(void) const
getActiveVersions
ConfigurationTree getNode(const std::string &nodeString, bool doNotThrowOnBrokenUIDLinks=false) const
"root/parent/parent/"
void init(std::string *accumulatedErrors=0, bool initForWriteAccess=false, std::string *accumulatedWarnings=0)
std::vector< std::pair< std::string, ConfigurationTree > > getChildren(std::map< std::string, TableVersion > *memberMap=0, std::string *accumulatedTreeErrors=0) const
static void getConfigurationStatusXML(HttpXmlDocument &xmlOut, ConfigurationManagerRW *cfgMgr, const std::string &username)
getConfigurationStatusXML
static void handleGetTableGroupXML(HttpXmlDocument &xmlOut, ConfigurationManagerRW *cfgMgr, const std::string &groupName, TableGroupKey groupKey, bool ignoreWarnings=false, bool cacheOnly=false)
static TableVersion saveModifiedVersionXML(HttpXmlDocument &xmlOut, ConfigurationManagerRW *cfgMgr, const std::string &tableName, TableVersion originalVersion, bool makeTemporary, TableBase *config, TableVersion temporaryModifiedVersion, bool ignoreDuplicates=false, bool lookForEquivalent=false)
static void handleCreateTableXML(HttpXmlDocument &xmlOut, ConfigurationManagerRW *cfgMgr, const std::string &tableName, TableVersion version, bool makeTemporary, const std::string &data, const int &dataOffset, const std::string &author, const std::string &comment, bool sourceTableAsIs, bool lookForEquivalent)
static void handleCreateTableGroupXML(HttpXmlDocument &xmlOut, ConfigurationManagerRW *cfgMgr, const std::string &groupName, const std::string &configList, bool allowDuplicates=false, bool ignoreWarnings=false, const std::string &groupComment="", bool lookForEquivalent=false)
std::vector< std::pair< std::string, ConfigurationTree > > getChildren(std::map< std::string, std::string > filterMap=std::map< std::string, std::string >(), bool byPriority=false, bool onlyStatusTrue=false) const
TableVersion createTemporaryView(TableVersion sourceViewVersion=TableVersion(), TableVersion destTemporaryViewVersion=TableVersion::getNextTemporaryVersion())
source of -1, from MockUp, else from valid view version
Definition: TableBase.cc:1734
TableView * getTemporaryView(TableVersion temporaryVersion)
Definition: TableBase.cc:1845
const TableVersion & getViewVersion(void) const
always the active one
Definition: TableBase.cc:823
std::string toString(void) const
toString
bool isInvalid(void) const
isInvalid
bool isMockupVersion(void) const
std::string toString(void) const
toString
Definition: TableVersion.cc:33
bool isInvalid(void) const
isInvalid
bool isScratchVersion(void) const
bool isTemporaryVersion(void) const
unsigned int findRow(unsigned int col, const T &value, unsigned int offsetRow=0, bool doNotThrow=false) const
< in included .icc source
void setValueAsString(const std::string &value, unsigned int row, unsigned int col)
Definition: TableView.cc:1090
unsigned int getColStatus(void) const
Definition: TableView.cc:1407
bool removeRowFromGroup(const unsigned int &row, const unsigned int &col, const std::string &groupID, bool deleteRowIfNoGroupLeft=false)
Definition: TableView.cc:1599
unsigned int copyRows(const std::string &author, const TableView &src, unsigned int srcOffsetRow=0, unsigned int srcRowsToCopy=(unsigned int) -1, unsigned int destOffsetRow=(unsigned int) -1, unsigned char generateUniqueDataColumns=false, const std::string &baseNameAutoUID="")
Definition: TableView.cc:126
void init(void)
Definition: TableView.cc:195
std::vector< unsigned int > getGroupRows(const unsigned int groupIdCol, const std::string &groupID, bool onlyStatusTrue=false, bool orderedByPriority=false) const
Definition: TableView.cc:1497
unsigned int getDataColumnSize(void) const
getDataColumnSize
Definition: TableView.cc:1992
unsigned int getColUID(void) const
Definition: TableView.cc:1322
bool setURIEncodedValue(const std::string &value, const unsigned int &row, const unsigned int &col, const std::string &author="")
Definition: TableView.cc:3425
int fillFromEncodedCSV(const std::string &data, const int &dataOffset=0, const std::string &author="")
Definition: TableView.cc:3289
unsigned int findCol(const std::string &name) const
Definition: TableView.cc:1952
void setURIEncodedComment(const std::string &uriComment)
Definition: TableView.cc:2107
unsigned int addRow(const std::string &author="", unsigned char incrementUniqueData=false, const std::string &baseNameAutoUID="", unsigned int rowToAdd=(unsigned int) -1, std::string childLinkIndex="", std::string groupId="")
Definition: TableView.cc:3517
xercesc::DOMElement * addTextElementToParent(const std::string &childName, const std::string &childText, xercesc::DOMElement *parent)
Definition: XmlDocument.cc:244
static std::string setToString(const std::set< T > &setToReturn, const std::string &delimeter=", ")
setToString ~
static std::string vectorToString(const std::vector< T > &setToReturn, const std::string &delimeter=", ")
vectorToString ~
static std::string mapToString(const std::map< std::string, T > &mapToReturn, const std::string &primaryDelimeter=", ", const std::string &secondaryDelimeter=": ")
static void getMapFromString(const std::string &inputString, std::map< S, T > &mapToReturn, const std::set< char > &pairPairDelimiter={',', '|', '&'}, const std::set< char > &nameValueDelimiter={'=', ':'}, const std::set< char > &whitespace={' ', '\t', '\n', '\r'})
getMapFromString ~
static std::string decodeURIComponent(const std::string &data)