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  // //add lo and hi spans, instead of each individual value
900  // size_t lo = -1, hi = -1;
901  // for(auto& keyInOrder : sortedKeys)
902  // {
903  // if(lo == size_t(-1)) //establish start of potential span
904  // {
905  // hi = lo = keyInOrder.key();
906  // continue;
907  // }
908  // else if(hi + 1 == keyInOrder.key()) //span is growing
909  // {
910  // hi = keyInOrder.key();
911  // continue;
912  // }
913  // //else jump by more than one, so close out span
914 
915  // if(lo == hi) //single value
916  // xmlOut.addNumberElementToData("HistoricalTableGroupKey", lo);
917  // else //span
918  // xmlOut.addTextElementToData("HistoricalTableGroupKey",
919  // "_" + std::to_string(lo) + "_" + std::to_string(hi));
920  // lo = -1;
921  // }
922  // //need to do last one!
923  // if(lo == hi) //single value
924  // xmlOut.addNumberElementToData("HistoricalTableGroupKey", lo);
925  // else //span
926  // xmlOut.addTextElementToData("HistoricalTableGroupKey",
927  // "_" + std::to_string(lo) + "_" + std::to_string(hi));
928 
929  // for(auto& keyInOrder : sortedKeys)
930  // xmlOut.addTextElementToData("HistoricalTableGroupKey",
931  // keyInOrder.toString());
932  }
933  }
934  else
935  {
936  // add all other sorted keys for this groupName
937  SpanToXML(sortedKeys, xmlOut);
938  }
939 
940  if(cfgMgr->getActiveVersions().size() == 0)
941  {
942  __COUTT__
943  << "There are no active tables. Attempting to initialize active groups."
944  << __E__;
945  //if no active tables, attempt to init active groups (it should prevent confusing warnings to users complaining about a partially loaded configuration)
946  std::string tmpAccumulateWarnings;
947  cfgMgr->init(0 /*accumulatedErrors*/,
948  false /*initForWriteAccess*/,
949  &tmpAccumulateWarnings);
950  __COUTT__ << "Now Active tables: "
951  << StringMacros::mapToString(cfgMgr->getActiveVersions()) << __E__;
952  __COUTT__ << "Ingoring warnings during init of active groups: "
953  << tmpAccumulateWarnings << __E__;
954  }
955  }
956 
957  xmlOut.addTextElementToData("TableGroupName", groupName);
958  xmlOut.addTextElementToData("TableGroupKey", groupKey.toString());
959 
960  parentEl = xmlOut.addTextElementToData("TableGroupMembers", "");
961 
962  // get specific group with key
963  std::map<std::string /*name*/, TableVersion /*version*/> memberMap;
964  std::map<std::string /*name*/, std::string /*alias*/> groupMemberAliases;
965 
966  __COUT__ << "groupName=" << groupName << __E__;
967  __COUT__ << "groupKey=" << groupKey << __E__;
968 
969  const std::map<std::string, TableInfo>& allTableInfo = cfgMgr->getAllTableInfo();
970  std::map<std::string, TableInfo>::const_iterator it;
971 
972  // load group so comments can be had
973  // and also group metadata (author, comment, createTime)
974  try
975  {
976  std::string groupAuthor, groupComment, groupCreationTime, groupTypeString;
977  std::string accumulateTreeErrors;
978 
979  __COUTV__(ignoreWarnings);
980  cfgMgr->loadTableGroup(groupName,
981  groupKey,
982  false /*doActivate*/,
983  &memberMap,
984  0 /*progressBar*/,
985  ignoreWarnings ? 0 : /*accumulateTreeErrors*/
986  &accumulateTreeErrors,
987  &groupComment,
988  &groupAuthor,
989  &groupCreationTime,
990  false /*doNotLoadMember*/,
991  &groupTypeString,
992  &groupMemberAliases);
993 
994  if(accumulateTreeErrors != "")
995  {
996  __COUTV__(accumulateTreeErrors);
997  xmlOut.addTextElementToData("TreeErrors", accumulateTreeErrors);
998  }
999 
1000  xmlOut.addTextElementToData("TableGroupAuthor", groupAuthor);
1001  xmlOut.addTextElementToData("TableGroupComment", groupComment);
1002  xmlOut.addTextElementToData("TableGroupCreationTime", groupCreationTime);
1003  xmlOut.addTextElementToData("TableGroupType", groupTypeString);
1004  }
1005  catch(const std::runtime_error& e)
1006  {
1007  __SS__ << "Table group \"" + groupName + "(" + groupKey.toString() + ")" +
1008  "\" members can not be loaded!\n\n" + e.what()
1009  << __E__;
1010  __COUT_ERR__ << ss.str();
1011  xmlOut.addTextElementToData("Error", ss.str());
1012  // return;
1013  }
1014  catch(...)
1015  {
1016  __SS__ << "Table group \"" + groupName + "(" + groupKey.toString() + ")" +
1017  "\" members can not be loaded!"
1018  << __E__;
1019  try
1020  {
1021  throw;
1022  } //one more try to printout extra info
1023  catch(const std::exception& e)
1024  {
1025  ss << "Exception message: " << e.what();
1026  }
1027  catch(...)
1028  {
1029  }
1030  __COUT_ERR__ << ss.str();
1031  xmlOut.addTextElementToData("Error", ss.str());
1032  // return;
1033  }
1034 
1035  __COUTV__(StringMacros::mapToString(groupMemberAliases));
1036 
1037  std::map<std::string, std::map<std::string, TableVersion>> versionAliases =
1038  cfgMgr->getVersionAliases();
1039 
1040  __COUT__ << "# of table version aliases: " << versionAliases.size() << __E__;
1041 
1042  // Seperate loop to get name and version
1043  for(auto& memberPair : memberMap)
1044  {
1045  xmlOut.addTextElementToParent("MemberName", memberPair.first, parentEl);
1046 
1047  // if member is in groupMemberAliases, then alias version
1048  if(groupMemberAliases.find(memberPair.first) != groupMemberAliases.end())
1049  configEl = xmlOut.addTextElementToParent(
1050  "MemberVersion",
1051  ConfigurationManager::ALIAS_VERSION_PREAMBLE +
1052  groupMemberAliases[memberPair.first], // return the ALIAS:<alias>
1053  parentEl);
1054  else
1055  configEl = xmlOut.addTextElementToParent(
1056  "MemberVersion", memberPair.second.toString(), parentEl);
1057 
1058  it = allTableInfo.find(memberPair.first);
1059  if(it == allTableInfo.end())
1060  {
1061  if(!cacheOnly) //only an 'error' if not cacheOnly
1062  xmlOut.addTextElementToData(
1063  "Error", "Table \"" + memberPair.first + "\" can not be retrieved!");
1064  continue;
1065  }
1066 
1067  xmlOut.addTextElementToParent(
1068  "MemberComment", it->second.tablePtr_->getView().getComment(), parentEl);
1069 
1070  if(versionAliases.find(it->first) != versionAliases.end())
1071  for(auto& aliasVersion : versionAliases[it->first])
1072  xmlOut.addTextElementToParent(
1073  "TableExistingVersion",
1074  ConfigurationManager::ALIAS_VERSION_PREAMBLE + aliasVersion.first,
1075  configEl);
1076 
1077  vSpanToXML(it->second.versions_, xmlOut, configEl);
1078  // //add lo and hi spans, instead of each individual value
1079  // size_t lo = -1, hi = -1;
1080  // for(auto& version : it->second.versions_)
1081  // {
1082  // if(lo == size_t(-1)) //establish start of potential span
1083  // {
1084  // hi = lo = version.version();
1085  // continue;
1086  // }
1087  // else if(hi + 1 == version.version()) //span is growing
1088  // {
1089  // hi = version.version();
1090  // continue;
1091  // }
1092  // //else jump by more than one, so close out span
1093 
1094  // if(lo == hi) //single value
1095  // xmlOut.addNumberElementToParent("TableExistingVersion", lo, configEl);
1096  // else //span
1097  // xmlOut.addTextElementToParent("TableExistingVersion",
1098  // "_" + std::to_string(lo) + "_" + std::to_string(hi), configEl);
1099  // lo = -1;
1100  // }
1101  // //need to do last one!
1102  // if(lo == hi) //single value
1103  // xmlOut.addNumberElementToParent("TableExistingVersion", lo, configEl);
1104  // else //span
1105  // xmlOut.addTextElementToParent("TableExistingVersion",
1106  // "_" + std::to_string(lo) + "_" + std::to_string(hi), configEl);
1107  // // for(auto& version : it->second.versions_)
1108  // // xmlOut.addTextElementToParent(
1109  // // "TableExistingVersion", version.toString(), configEl);
1110  } //end member map loop
1111 
1112  // // Seperate loop just for getting the Member Comment
1113  // for(auto& memberPair : memberMap)
1114  // {
1115  // //__COUT__ << "\tMember table " << memberPair.first << ":" <<
1116  // // memberPair.second << __E__;
1117 
1118  // // xmlOut.addTextElementToParent("MemberName", memberPair.first, parentEl);
1119  // // if(commentsLoaded)
1120  // xmlOut.addTextElementToParent(
1121  // "MemberComment",
1122  // allTableInfo.at(memberPair.first).tablePtr_->getView().getComment(),
1123  // parentEl);
1124  // // else
1125  // // xmlOut.addTextElementToParent("MemberComment", "", parentEl);
1126 
1127  // // __COUT__ << "\tMember table " << memberPair.first << ":" <<
1128  // // memberPair.second << __E__;
1129 
1130  // // configEl = xmlOut.addTextElementToParent("MemberVersion",
1131  // // memberPair.second.toString(), parentEl);
1132 
1133  // /* it = allTableInfo.find(memberPair.first);
1134  // if(it == allTableInfo.end())
1135  // {
1136  // xmlOut.addTextElementToData("Error","Table \"" +
1137  // memberPair.first +
1138  // "\" can not be retrieved!");
1139  // return;
1140  // }
1141  // */
1142  // // include aliases for this table
1143  // /*if(versionAliases.find(it->first) != versionAliases.end())
1144  // for (auto& aliasVersion:versionAliases[it->first])
1145  // xmlOut.addTextElementToParent("TableExistingVersion",
1146  // ConfigurationManager::ALIAS_VERSION_PREAMBLE + aliasVersion.first,
1147  // configEl);
1148 
1149  // for (auto& version:it->second.versions_)
1150  // //if(version == memberPair.second) continue; //CHANGED by RAR on 11/14/2016
1151  // (might as well show all versions in list to avoid user confusion)
1152  // //else
1153  // xmlOut.addTextElementToParent("TableExistingVersion",
1154  // version.toString(), configEl);
1155  // */
1156  // }
1157 
1158 } // end handleGetTableGroupXML()
1159 catch(std::runtime_error& e)
1160 {
1161  __SS__ << ("Error getting table group!\n\n" + std::string(e.what())) << __E__;
1162  __COUT_ERR__ << "\n" << ss.str();
1163  xmlOut.addTextElementToData("Error", ss.str());
1164 }
1165 catch(...)
1166 {
1167  __SS__ << ("Error getting table group!\n\n") << __E__;
1168  try
1169  {
1170  throw;
1171  } //one more try to printout extra info
1172  catch(const std::exception& e)
1173  {
1174  ss << "Exception message: " << e.what();
1175  }
1176  catch(...)
1177  {
1178  }
1179  __COUT_ERR__ << "\n" << ss.str();
1180  xmlOut.addTextElementToData("Error", ss.str());
1181 } // end handleGetTableGroupXML() catch
1182 
1183 //==============================================================================
1184 bool ConfigurationSupervisorBase::handleAddDesktopIconXML(
1185  HttpXmlDocument& xmlOut,
1186  ConfigurationManagerRW* cfgMgr,
1187  const std::string& iconCaption,
1188  const std::string& iconAltText,
1189  const std::string& iconFolderPath,
1190  const std::string& iconImageURL,
1191  const std::string& iconWindowURL,
1192  const std::string& iconPermissions,
1193  std::string windowLinkedApp /*= ""*/,
1194  unsigned int windowLinkedAppLID /*= 0*/,
1195  bool enforceOneWindowInstance /*= false*/,
1196  const std::string& windowParameters /*= ""*/)
1197 try
1198 {
1199  cfgMgr->getAllTableInfo(true /* refresh */);
1200 
1201  const std::string& author = cfgMgr->getUsername();
1202 
1203  __COUTV__(author);
1204  __COUTV__(iconCaption);
1205  __COUTV__(iconAltText);
1206  __COUTV__(iconFolderPath);
1207  __COUTV__(iconImageURL);
1208  __COUTV__(iconWindowURL);
1209  __COUTV__(iconPermissions);
1210  __COUTV__(windowLinkedApp);
1211  __COUTV__(windowLinkedAppLID);
1212  __COUTV__(enforceOneWindowInstance);
1213 
1214  __COUTV__(windowParameters); // map: CSV list
1215 
1216  // steps:
1217  // activate active context
1218  // modify desktop table and desktop parameters table
1219  // save, activate, and modify alias
1220  // just to match syntax in ConfiguratGUI
1221  // tmpCfgMgr.activateTableGroup(
1222  // tmpCfgMgr.getActiveGroupName(ConfigurationManager::GROUP_TYPE_NAME_CONTEXT),
1223  // tmpCfgMgr.getActiveGroupKey(ConfigurationManager::GROUP_TYPE_NAME_CONTEXT)
1224  // );
1225 
1226  cfgMgr->restoreActiveTableGroups(
1227  true /*throwErrors*/,
1228  "" /*pathToActiveGroupsFile*/,
1229  ConfigurationManager::LoadGroupType::
1230  ONLY_BACKBONE_OR_CONTEXT_TYPES /*onlyLoadIfBackboneOrContext*/
1231  );
1232 
1233  const std::string backboneGroupName =
1234  cfgMgr->getActiveGroupName(ConfigurationManager::GroupType::BACKBONE_TYPE);
1235 
1236  GroupEditStruct contextGroupEdit(ConfigurationManager::GroupType::CONTEXT_TYPE,
1237  cfgMgr);
1238 
1239  // Steps:
1240  // - Create record in DesktopIconTable
1241  // - Create parameter records in DesktopWindowParameterTable
1242  // - Create new Context group
1243  // - Update Aliases from old Context group to new Context group
1244  // - Activate new group
1245 
1246  TableEditStruct& iconTable = contextGroupEdit.getTableEditStruct(
1247  DesktopIconTable::ICON_TABLE, true /*markModified*/);
1248  TableEditStruct& parameterTable = contextGroupEdit.getTableEditStruct(
1249  DesktopIconTable::PARAMETER_TABLE, true /*markModified*/);
1250  TableEditStruct& appTable = contextGroupEdit.getTableEditStruct(
1251  ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME);
1252 
1253  // Create record in DesktopIconTable
1254  try
1255  {
1256  unsigned int row;
1257  std::string iconUID = "";
1258  std::string decodedCaption = StringMacros::decodeURIComponent(iconCaption);
1259 
1260  for(unsigned int i = 0; i < decodedCaption.size(); ++i)
1261  if((decodedCaption[i] >= 'a' && decodedCaption[i] <= 'z') ||
1262  (decodedCaption[i] >= 'A' && decodedCaption[i] <= 'Z') ||
1263  (decodedCaption[i] >= '0' && decodedCaption[i] <= '9'))
1264  iconUID += decodedCaption[i];
1265 
1266  // create icon record
1267  row = iconTable.tableView_->addRow(
1268  author, true /*incrementUniqueData*/, "generatedIcon" + iconUID);
1269  iconUID =
1270  iconTable.tableView_->getDataView()[row][iconTable.tableView_->getColUID()];
1271 
1272  __COUTV__(row);
1273  __COUTV__(iconUID);
1274 
1275  // set icon status true
1276  iconTable.tableView_->setValueAsString(
1277  "1", row, iconTable.tableView_->getColStatus());
1278 
1279  // set caption value
1280  iconTable.tableView_->setURIEncodedValue(
1281  iconCaption,
1282  row,
1283  iconTable.tableView_->findCol(DesktopIconTable::COL_CAPTION));
1284  // set alt text value
1285  iconTable.tableView_->setURIEncodedValue(
1286  iconAltText,
1287  row,
1288  iconTable.tableView_->findCol(DesktopIconTable::COL_ALTERNATE_TEXT));
1289  // set force one instance value
1290  iconTable.tableView_->setValueAsString(
1291  enforceOneWindowInstance ? "1" : "0",
1292  row,
1293  iconTable.tableView_->findCol(DesktopIconTable::COL_FORCE_ONLY_ONE_INSTANCE));
1294  // set permissions value
1295  iconTable.tableView_->setURIEncodedValue(
1296  iconPermissions,
1297  row,
1298  iconTable.tableView_->findCol(DesktopIconTable::COL_PERMISSIONS));
1299  // set image URL value
1300  iconTable.tableView_->setURIEncodedValue(
1301  iconImageURL,
1302  row,
1303  iconTable.tableView_->findCol(DesktopIconTable::COL_IMAGE_URL));
1304  // set window URL value
1305  iconTable.tableView_->setURIEncodedValue(
1306  iconWindowURL,
1307  row,
1308  iconTable.tableView_->findCol(DesktopIconTable::COL_WINDOW_CONTENT_URL));
1309  // set folder value
1310  iconTable.tableView_->setURIEncodedValue(
1311  iconFolderPath,
1312  row,
1313  iconTable.tableView_->findCol(DesktopIconTable::COL_FOLDER_PATH));
1314 
1315  // create link to icon app
1316  if(windowLinkedAppLID > 0)
1317  {
1318  __COUTV__(windowLinkedAppLID);
1319 
1320  int appRow = appTable.tableView_->findRow(
1321  appTable.tableView_->findCol(XDAQContextTable::colApplication_.colId_),
1322  windowLinkedAppLID);
1323  windowLinkedApp =
1324  appTable.tableView_
1325  ->getDataView()[appRow][appTable.tableView_->getColUID()];
1326  __COUT__ << "Found app by LID: " << windowLinkedApp << __E__;
1327  } // end linked app LID handling
1328 
1329  if(windowLinkedApp != "" && windowLinkedApp != "undefined" &&
1330  windowLinkedApp != TableViewColumnInfo::DATATYPE_STRING_DEFAULT)
1331  {
1332  // first check that UID exists
1333  // if not, interpret as app class type and
1334  // check for unique 'enabled' app with class type
1335  __COUTV__(windowLinkedApp);
1336 
1337  if(!windowLinkedAppLID) // no need to check if LID lookup happened already
1338  {
1339  try
1340  {
1341  windowLinkedApp = StringMacros::decodeURIComponent(windowLinkedApp);
1342  /* int appRow = */ appTable.tableView_->findRow(
1343  appTable.tableView_->getColUID(), windowLinkedApp);
1344  }
1345  catch(const std::runtime_error& e)
1346  {
1347  // attempt to treat like class, and take first match
1348  try
1349  {
1350  int appRow = appTable.tableView_->findRow(
1351  appTable.tableView_->findCol(
1352  XDAQContextTable::colApplication_.colClass_),
1353  windowLinkedApp);
1354  windowLinkedApp =
1355  appTable.tableView_
1356  ->getDataView()[appRow][appTable.tableView_->getColUID()];
1357  }
1358  catch(...)
1359  {
1360  // failed to treat like class, so throw original
1361  __SS__
1362  << "Failed to create an icon linking to XDAQ Supervisor app '"
1363  << windowLinkedApp
1364  << ".' Please make sure the Supervisor exists in the "
1365  << ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME
1366  << " table. "
1367  << "\n\nThe following error occurred: " << e.what() << __E__;
1368  appTable.tableView_->print(ss);
1369  __SS_THROW__;
1370  }
1371  }
1372  }
1373  __COUTV__(windowLinkedApp);
1374 
1375  iconTable.tableView_->setValueAsString(
1376  ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME,
1377  row,
1378  iconTable.tableView_->findCol(DesktopIconTable::COL_APP_LINK));
1379  iconTable.tableView_->setValueAsString(
1380  windowLinkedApp,
1381  row,
1382  iconTable.tableView_->findCol(DesktopIconTable::COL_APP_LINK_UID));
1383  } // end create app link
1384 
1385  // parse parameters
1386  std::map<std::string, std::string> parameters;
1387 
1388  __COUTV__(windowParameters);
1389  StringMacros::getMapFromString(windowParameters, parameters);
1390 
1391  // create link to icon parameters
1392  if(parameters.size())
1393  {
1394  // set parameter link table
1395  iconTable.tableView_->setValueAsString(
1396  DesktopIconTable::PARAMETER_TABLE,
1397  row,
1398  iconTable.tableView_->findCol(DesktopIconTable::COL_PARAMETER_LINK));
1399  // set parameter link Group ID
1400  iconTable.tableView_->setValueAsString(
1401  iconUID + "_Parameters",
1402  row,
1403  iconTable.tableView_->findCol(DesktopIconTable::COL_PARAMETER_LINK_GID));
1404 
1405  __COUTV__(StringMacros::mapToString(parameters));
1406 
1407  unsigned int gidCol =
1408  parameterTable.tableView_->findCol(DesktopIconTable::COL_PARAMETER_GID);
1409 
1410  // remove all existing records from groupID (e.g. parameters leftover from manual manipulations)
1411  std::vector<unsigned int /*row*/> rowsInGroup =
1412  parameterTable.tableView_->getGroupRows(
1413  gidCol, iconUID + "_Parameters" /*groupID*/);
1414 
1415  __COUTV__(StringMacros::vectorToString(rowsInGroup));
1416 
1417  // go through vector backwards to maintain row integrity
1418  for(unsigned int r = rowsInGroup.size() - 1; r < rowsInGroup.size(); --r)
1419  parameterTable.tableView_->removeRowFromGroup(
1420  rowsInGroup[r],
1421  gidCol,
1422  iconUID + "_Parameters" /*groupID*/,
1423  true /*deleteRowIfNoGroupLeft*/);
1424 
1425  // create new parameters
1426  for(const auto& parameter : parameters)
1427  {
1428  // create parameter record
1429  row = parameterTable.tableView_->addRow(
1430  author, true /*incrementUniqueData*/, "generatedParameter");
1431 
1432  // set parameter status true
1433  parameterTable.tableView_->setValueAsString(
1434  "1", row, parameterTable.tableView_->getColStatus());
1435  // set parameter Group ID
1436  parameterTable.tableView_->setValueAsString(
1437  iconUID + "_Parameters", row, gidCol);
1438  // set parameter key
1439  parameterTable.tableView_->setURIEncodedValue(
1440  parameter.first,
1441  row,
1442  parameterTable.tableView_->findCol(
1443  DesktopIconTable::COL_PARAMETER_KEY));
1444  // set parameter value
1445  parameterTable.tableView_->setURIEncodedValue(
1446  parameter.second,
1447  row,
1448  parameterTable.tableView_->findCol(
1449  DesktopIconTable::COL_PARAMETER_VALUE));
1450  } // end parameter loop
1451 
1452  std::stringstream ss;
1453  parameterTable.tableView_->print(ss);
1454  __COUT__ << ss.str();
1455 
1456  parameterTable.tableView_
1457  ->init(); // verify new table (throws runtime_errors)
1458 
1459  } // end create parameters link
1460 
1461  std::stringstream ss;
1462  iconTable.tableView_->print(ss);
1463  __COUT__ << ss.str();
1464 
1465  iconTable.tableView_->init(); // verify new table (throws runtime_errors)
1466  }
1467  catch(...)
1468  {
1469  __COUT__ << "Icon table errors while saving. Erasing all newly "
1470  "created table versions."
1471  << __E__;
1472 
1473  throw; // re-throw
1474  } // end catch
1475 
1476  __COUT__ << "Edits complete for new desktop icon, now making persistent tables."
1477  << __E__;
1478 
1479  // all edits are complete and tables verified
1480 
1481  // Remaining steps:
1482  // save tables
1483  // save new context group and activate it
1484  // check for aliases ...
1485  // if tables aliased.. update table aliases in backbone
1486  // if context group aliased, update group aliases in backbone
1487  // if backbone modified, save group and activate it
1488 
1489  TableGroupKey newContextKey;
1490  bool foundEquivalentContextKey;
1491  TableGroupKey newBackboneKey;
1492  bool foundEquivalentBackboneKey;
1493 
1494  contextGroupEdit.saveChanges(contextGroupEdit.originalGroupName_,
1495  newContextKey,
1496  &foundEquivalentContextKey,
1497  true /*activateNewGroup*/,
1498  true /*updateGroupAliases*/,
1499  true /*updateTableAliases*/,
1500  &newBackboneKey,
1501  &foundEquivalentBackboneKey);
1502 
1503  xmlOut.addTextElementToData("contextGroupName", contextGroupEdit.originalGroupName_);
1504  xmlOut.addTextElementToData("contextGroupKey", newContextKey.toString());
1505 
1506  xmlOut.addTextElementToData("backboneGroupName", backboneGroupName);
1507  xmlOut.addTextElementToData("backboneGroupKey", newBackboneKey.toString());
1508 
1509  // always add active table groups to xml response
1511 
1512  return true;
1513  //---------------------------------------------------
1514 
1515  if(0)
1516  {
1517  // save map of group members get context members active table versions
1518  std::map<std::string, TableVersion> contextGroupMembers;
1519  std::map<std::string, TableVersion> backboneGroupMembers;
1520  {
1521  std::map<std::string, TableVersion> activeTables =
1522  cfgMgr->getActiveVersions();
1523  for(auto& table : cfgMgr->getContextMemberNames())
1524  try
1525  {
1526  __COUT__ << table << " v" << activeTables.at(table) << __E__;
1527  contextGroupMembers[table] = activeTables.at(table);
1528  }
1529  catch(...)
1530  {
1531  __SS__
1532  << "Error! Could not find Context member table '" << table
1533  << ".' All Context members must be present to add a desktop icon."
1534  << __E__;
1535  __SS_THROW__;
1536  }
1537  for(auto& table : cfgMgr->getBackboneMemberNames())
1538  try
1539  {
1540  __COUT__ << table << " v" << activeTables.at(table) << __E__;
1541  backboneGroupMembers[table] = activeTables.at(table);
1542  }
1543  catch(...)
1544  {
1545  __SS__ << "Error! Could not find Backbone member table '" << table
1546  << ".' All Backbone members must be present to add a desktop "
1547  "icon."
1548  << __E__;
1549  __SS_THROW__;
1550  }
1551  }
1552 
1553  const std::string contextGroupName =
1554  cfgMgr->getActiveGroupName(ConfigurationManager::GroupType::CONTEXT_TYPE);
1555  const TableGroupKey originalContextGroupKey =
1556  cfgMgr->getActiveGroupKey(ConfigurationManager::GroupType::CONTEXT_TYPE);
1557  const std::string backboneGroupName =
1558  cfgMgr->getActiveGroupName(ConfigurationManager::GroupType::BACKBONE_TYPE);
1559  const TableGroupKey originalBackboneGroupKey =
1560  cfgMgr->getActiveGroupKey(ConfigurationManager::GroupType::BACKBONE_TYPE);
1561 
1562  __COUTV__(contextGroupName);
1563  __COUTV__(originalContextGroupKey);
1564  __COUTV__(backboneGroupName);
1565  __COUTV__(originalBackboneGroupKey);
1566 
1567  if(contextGroupName == "" || originalContextGroupKey.isInvalid())
1568  {
1569  __SS__ << "Error! No active Context group found. "
1570  "There must be an active Context group to add a Desktop Icon."
1571  << __E__;
1572  __SS_THROW__;
1573  }
1574 
1575  // Steps:
1576  // - Create record in DesktopIconTable
1577  // - Create parameter records in DesktopWindowParameterTable
1578  // - Create new Context group
1579  // - Update Aliases from old Context group to new Context group
1580  // - Activate new group
1581 
1582  TableEditStruct iconTable(DesktopIconTable::ICON_TABLE,
1583  cfgMgr); // Table ready for editing!
1584  TableEditStruct parameterTable(DesktopIconTable::PARAMETER_TABLE,
1585  cfgMgr); // Table ready for editing!
1586  TableEditStruct appTable(ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME,
1587  cfgMgr); // Table ready for editing!
1588 
1589  // Create record in DesktopIconTable
1590  try
1591  {
1592  unsigned int row;
1593  std::string iconUID;
1594 
1595  // create icon record
1596  row = iconTable.tableView_->addRow(
1597  author, true /*incrementUniqueData*/, "generatedIcon");
1598  iconUID = iconTable.tableView_
1599  ->getDataView()[row][iconTable.tableView_->getColUID()];
1600 
1601  __COUTV__(row);
1602  __COUTV__(iconUID);
1603 
1604  // set icon status true
1605  iconTable.tableView_->setValueAsString(
1606  "1", row, iconTable.tableView_->getColStatus());
1607 
1608  // set caption value
1609  iconTable.tableView_->setURIEncodedValue(
1610  iconCaption,
1611  row,
1612  iconTable.tableView_->findCol(DesktopIconTable::COL_CAPTION));
1613  // set alt text value
1614  iconTable.tableView_->setURIEncodedValue(
1615  iconAltText,
1616  row,
1617  iconTable.tableView_->findCol(DesktopIconTable::COL_ALTERNATE_TEXT));
1618  // set force one instance value
1619  iconTable.tableView_->setValueAsString(
1620  enforceOneWindowInstance ? "1" : "0",
1621  row,
1622  iconTable.tableView_->findCol(
1623  DesktopIconTable::COL_FORCE_ONLY_ONE_INSTANCE));
1624  // set permissions value
1625  iconTable.tableView_->setURIEncodedValue(
1626  iconPermissions,
1627  row,
1628  iconTable.tableView_->findCol(DesktopIconTable::COL_PERMISSIONS));
1629  // set image URL value
1630  iconTable.tableView_->setURIEncodedValue(
1631  iconImageURL,
1632  row,
1633  iconTable.tableView_->findCol(DesktopIconTable::COL_IMAGE_URL));
1634  // set window URL value
1635  iconTable.tableView_->setURIEncodedValue(
1636  iconWindowURL,
1637  row,
1638  iconTable.tableView_->findCol(DesktopIconTable::COL_WINDOW_CONTENT_URL));
1639  // set folder value
1640  iconTable.tableView_->setURIEncodedValue(
1641  iconFolderPath,
1642  row,
1643  iconTable.tableView_->findCol(DesktopIconTable::COL_FOLDER_PATH));
1644 
1645  // create link to icon app
1646  if(windowLinkedAppLID > 0)
1647  {
1648  __COUTV__(windowLinkedAppLID);
1649 
1650  int appRow = appTable.tableView_->findRow(
1651  appTable.tableView_->findCol(
1652  XDAQContextTable::colApplication_.colId_),
1653  windowLinkedAppLID);
1654  windowLinkedApp =
1655  appTable.tableView_
1656  ->getDataView()[appRow][appTable.tableView_->getColUID()];
1657  __COUT__ << "Found app by LID: " << windowLinkedApp << __E__;
1658  } // end linked app LID handling
1659 
1660  if(windowLinkedApp != "" && windowLinkedApp != "undefined" &&
1661  windowLinkedApp != TableViewColumnInfo::DATATYPE_STRING_DEFAULT)
1662  {
1663  // first check that UID exists
1664  // if not, interpret as app class type and
1665  // check for unique 'enabled' app with class type
1666  __COUTV__(windowLinkedApp);
1667 
1668  if(!windowLinkedAppLID) // no need to check if LID lookup happened already
1669  {
1670  try
1671  {
1672  /*int appRow =*/appTable.tableView_->findRow(
1673  appTable.tableView_->getColUID(), windowLinkedApp);
1674  }
1675  catch(const std::runtime_error& e)
1676  {
1677  // attempt to treat like class, and take first match
1678  try
1679  {
1680  int appRow = appTable.tableView_->findRow(
1681  appTable.tableView_->findCol(
1682  XDAQContextTable::colApplication_.colClass_),
1683  windowLinkedApp);
1684  windowLinkedApp =
1685  appTable.tableView_
1686  ->getDataView()[appRow]
1687  [appTable.tableView_->getColUID()];
1688  }
1689  catch(...)
1690  {
1691  // failed to treat like class, so throw original
1692  __SS__ << "Failed to create an icon linking to app '"
1693  << windowLinkedApp
1694  << ".' The following error occurred: " << e.what()
1695  << __E__;
1696  __SS_THROW__;
1697  }
1698  }
1699  }
1700  __COUTV__(windowLinkedApp);
1701 
1702  iconTable.tableView_->setValueAsString(
1703  ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME,
1704  row,
1705  iconTable.tableView_->findCol(DesktopIconTable::COL_APP_LINK));
1706  iconTable.tableView_->setValueAsString(
1707  windowLinkedApp,
1708  row,
1709  iconTable.tableView_->findCol(DesktopIconTable::COL_APP_LINK_UID));
1710  } // end create app link
1711 
1712  // parse parameters
1713  std::map<std::string, std::string> parameters;
1714 
1715  __COUTV__(windowParameters);
1716  StringMacros::getMapFromString(windowParameters, parameters);
1717 
1718  // create link to icon parameters
1719  if(parameters.size())
1720  {
1721  // set parameter link table
1722  iconTable.tableView_->setValueAsString(
1723  DesktopIconTable::PARAMETER_TABLE,
1724  row,
1725  iconTable.tableView_->findCol(DesktopIconTable::COL_PARAMETER_LINK));
1726  // set parameter link Group ID
1727  iconTable.tableView_->setValueAsString(
1728  iconUID + "_Parameters",
1729  row,
1730  iconTable.tableView_->findCol(
1731  DesktopIconTable::COL_PARAMETER_LINK_GID));
1732 
1733  __COUTV__(StringMacros::mapToString(parameters));
1734 
1735  for(const auto& parameter : parameters)
1736  {
1737  // create parameter record
1738  row = parameterTable.tableView_->addRow(
1739  author, true /*incrementUniqueData*/, "generatedParameter");
1740 
1741  // set parameter status true
1742  parameterTable.tableView_->setValueAsString(
1743  "1", row, parameterTable.tableView_->getColStatus());
1744  // set parameter Group ID
1745  parameterTable.tableView_->setValueAsString(
1746  iconUID + "_Parameters",
1747  row,
1748  parameterTable.tableView_->findCol(
1749  DesktopIconTable::COL_PARAMETER_GID));
1750  // set parameter key
1751  parameterTable.tableView_->setURIEncodedValue(
1752  parameter.first,
1753  row,
1754  parameterTable.tableView_->findCol(
1755  DesktopIconTable::COL_PARAMETER_KEY));
1756  // set parameter value
1757  parameterTable.tableView_->setURIEncodedValue(
1758  parameter.second,
1759  row,
1760  parameterTable.tableView_->findCol(
1761  DesktopIconTable::COL_PARAMETER_VALUE));
1762  } // end parameter loop
1763 
1764  std::stringstream ss;
1765  parameterTable.tableView_->print(ss);
1766  __COUT__ << ss.str();
1767 
1768  parameterTable.tableView_
1769  ->init(); // verify new table (throws runtime_errors)
1770 
1771  } // end create parameters link
1772 
1773  std::stringstream ss;
1774  iconTable.tableView_->print(ss);
1775  __COUT__ << ss.str();
1776 
1777  iconTable.tableView_->init(); // verify new table (throws runtime_errors)
1778  }
1779  catch(...)
1780  {
1781  __COUT__ << "Icon table errors while saving. Erasing all newly "
1782  "created table versions."
1783  << __E__;
1784  if(iconTable.createdTemporaryVersion_) // if temporary version created here
1785  {
1786  __COUT__ << "Erasing temporary version " << iconTable.tableName_ << "-v"
1787  << iconTable.temporaryVersion_ << __E__;
1788  // erase with proper version management
1789  cfgMgr->eraseTemporaryVersion(iconTable.tableName_,
1790  iconTable.temporaryVersion_);
1791  }
1792 
1793  if(parameterTable
1794  .createdTemporaryVersion_) // if temporary version created here
1795  {
1796  __COUT__ << "Erasing temporary version " << parameterTable.tableName_
1797  << "-v" << parameterTable.temporaryVersion_ << __E__;
1798  // erase with proper version management
1799  cfgMgr->eraseTemporaryVersion(parameterTable.tableName_,
1800  parameterTable.temporaryVersion_);
1801  }
1802 
1803  if(appTable.createdTemporaryVersion_) // if temporary version created here
1804  {
1805  __COUT__ << "Erasing temporary version " << appTable.tableName_ << "-v"
1806  << appTable.temporaryVersion_ << __E__;
1807  // erase with proper version management
1808  cfgMgr->eraseTemporaryVersion(appTable.tableName_,
1809  appTable.temporaryVersion_);
1810  }
1811 
1812  throw; // re-throw
1813  } // end catch
1814 
1815  __COUT__ << "Edits complete for new desktop icon, now making persistent tables."
1816  << __E__;
1817 
1818  // all edits are complete and tables verified
1819 
1820  // Remaining steps:
1821  // save tables
1822  // save new context group and activate it
1823  // check for aliases ...
1824  // if tables aliased.. update table aliases in backbone
1825  // if context group aliased, update group aliases in backbone
1826  // if backbone modified, save group and activate it
1827 
1828  __COUT__ << "Original version is " << iconTable.tableName_ << "-v"
1829  << iconTable.originalVersion_ << __E__;
1830  __COUT__ << "Original version is " << parameterTable.tableName_ << "-v"
1831  << parameterTable.originalVersion_ << __E__;
1832 
1833  contextGroupMembers[DesktopIconTable::ICON_TABLE] =
1835  xmlOut,
1836  cfgMgr,
1837  iconTable.tableName_,
1838  iconTable.originalVersion_,
1839  true /*make temporary*/,
1840  iconTable.table_,
1841  iconTable.temporaryVersion_,
1842  true /*ignoreDuplicates*/); // make temporary version to save persistent version properly
1843  contextGroupMembers[DesktopIconTable::PARAMETER_TABLE] =
1845  xmlOut,
1846  cfgMgr,
1847  parameterTable.tableName_,
1848  parameterTable.originalVersion_,
1849  true /*make temporary*/,
1850  parameterTable.table_,
1851  parameterTable.temporaryVersion_,
1852  true /*ignoreDuplicates*/); // make temporary version to save persistent version properly
1853 
1854  __COUT__ << "Temporary target version is " << iconTable.tableName_ << "-v"
1855  << contextGroupMembers[DesktopIconTable::ICON_TABLE] << "-v"
1856  << iconTable.temporaryVersion_ << __E__;
1857  __COUT__ << "Temporary target version is " << parameterTable.tableName_ << "-v"
1858  << contextGroupMembers[DesktopIconTable::PARAMETER_TABLE] << "-v"
1859  << parameterTable.temporaryVersion_ << __E__;
1860 
1861  contextGroupMembers[DesktopIconTable::ICON_TABLE] =
1863  xmlOut,
1864  cfgMgr,
1865  iconTable.tableName_,
1866  iconTable.originalVersion_,
1867  false /*make temporary*/,
1868  iconTable.table_,
1869  iconTable.temporaryVersion_,
1870  false /*ignoreDuplicates*/,
1871  true /*lookForEquivalent*/); // save persistent version properly
1872  contextGroupMembers[DesktopIconTable::PARAMETER_TABLE] =
1874  xmlOut,
1875  cfgMgr,
1876  parameterTable.tableName_,
1877  parameterTable.originalVersion_,
1878  false /*make temporary*/,
1879  parameterTable.table_,
1880  parameterTable.temporaryVersion_,
1881  false /*ignoreDuplicates*/,
1882  true /*lookForEquivalent*/); // save persistent version properly
1883 
1884  __COUT__ << "Final target version is " << iconTable.tableName_ << "-v"
1885  << contextGroupMembers[DesktopIconTable::ICON_TABLE] << __E__;
1886  __COUT__ << "Final target version is " << parameterTable.tableName_ << "-v"
1887  << contextGroupMembers[DesktopIconTable::PARAMETER_TABLE] << __E__;
1888 
1889  for(auto& table : contextGroupMembers)
1890  {
1891  __COUT__ << table.first << " v" << table.second << __E__;
1892  }
1893 
1894  __COUT__ << "Checking for duplicate Context groups..." << __E__;
1895  TableGroupKey newContextKey =
1896  cfgMgr->findTableGroup(contextGroupName, contextGroupMembers);
1897 
1898  if(!newContextKey.isInvalid())
1899  {
1900  __COUT__ << "Found equivalent group key (" << newContextKey << ") for "
1901  << contextGroupName << "." << __E__;
1902  xmlOut.addTextElementToData(contextGroupName + "_foundEquivalentKey",
1903  "1"); // indicator
1904  }
1905  else
1906  {
1907  newContextKey =
1908  cfgMgr->saveNewTableGroup(contextGroupName, contextGroupMembers);
1909  __COUT__ << "Saved new Context group key (" << newContextKey << ") for "
1910  << contextGroupName << "." << __E__;
1911  }
1912 
1913  xmlOut.addTextElementToData("contextGroupName", contextGroupName);
1914  xmlOut.addTextElementToData("contextGroupKey", newContextKey.toString());
1915 
1916  // check for aliases of original group key and original table version
1917 
1918  __COUT__ << "Original version is " << iconTable.tableName_ << "-v"
1919  << iconTable.originalVersion_ << __E__;
1920  __COUT__ << "Original version is " << parameterTable.tableName_ << "-v"
1921  << parameterTable.originalVersion_ << __E__;
1922 
1923  bool groupAliasChange = false;
1924  bool tableAliasChange = false;
1925 
1926  { // check group aliases ... a la
1927  // ConfigurationGUISupervisor::handleSetGroupAliasInBackboneXML
1928 
1929  TableBase* table =
1930  cfgMgr->getTableByName(ConfigurationManager::GROUP_ALIASES_TABLE_NAME);
1931  TableVersion originalVersion =
1932  backboneGroupMembers[ConfigurationManager::GROUP_ALIASES_TABLE_NAME];
1933  TableVersion temporaryVersion = table->createTemporaryView(originalVersion);
1934  TableView* tableView = table->getTemporaryView(temporaryVersion);
1935 
1936  // unsigned int col;
1937  unsigned int row = 0;
1938 
1939  std::vector<std::pair<std::string, ConfigurationTree>> aliasNodePairs =
1940  cfgMgr->getNode(ConfigurationManager::GROUP_ALIASES_TABLE_NAME)
1941  .getChildren();
1942  std::string groupName, groupKey;
1943  for(auto& aliasNodePair : aliasNodePairs)
1944  {
1945  groupName = aliasNodePair.second.getNode("GroupName").getValueAsString();
1946  groupKey = aliasNodePair.second.getNode("GroupKey").getValueAsString();
1947 
1948  __COUT__ << "Group Alias: " << aliasNodePair.first << " => " << groupName
1949  << "(" << groupKey << "); row=" << row << __E__;
1950 
1951  if(groupName == contextGroupName &&
1952  TableGroupKey(groupKey) == originalContextGroupKey)
1953  {
1954  __COUT__ << "Found alias! Changing group key." << __E__;
1955 
1956  groupAliasChange = true;
1957 
1958  tableView->setValueAsString(
1959  newContextKey.toString(), row, tableView->findCol("GroupKey"));
1960  }
1961 
1962  ++row;
1963  }
1964 
1965  if(groupAliasChange)
1966  {
1967  std::stringstream ss;
1968  tableView->print(ss);
1969  __COUT__ << ss.str();
1970 
1971  // save or find equivalent
1972  backboneGroupMembers[ConfigurationManager::GROUP_ALIASES_TABLE_NAME] =
1974  xmlOut,
1975  cfgMgr,
1976  table->getTableName(),
1977  originalVersion,
1978  false /*makeTemporary*/,
1979  table,
1980  temporaryVersion,
1981  false /*ignoreDuplicates*/,
1982  true /*lookForEquivalent*/);
1983 
1984  __COUT__ << "Original version is " << table->getTableName() << "-v"
1985  << originalVersion << " and new version is v"
1986  << backboneGroupMembers
1987  [ConfigurationManager::GROUP_ALIASES_TABLE_NAME]
1988  << __E__;
1989  }
1990 
1991  } // end group alias check
1992 
1993  { // check version aliases
1994 
1995  TableBase* table =
1996  cfgMgr->getTableByName(ConfigurationManager::VERSION_ALIASES_TABLE_NAME);
1997  TableVersion originalVersion =
1998  backboneGroupMembers[ConfigurationManager::VERSION_ALIASES_TABLE_NAME];
1999  TableVersion temporaryVersion = table->createTemporaryView(originalVersion);
2000  TableView* tableView = table->getTemporaryView(temporaryVersion);
2001 
2002  // unsigned int col;
2003  unsigned int row = 0;
2004 
2005  std::vector<std::pair<std::string, ConfigurationTree>> aliasNodePairs =
2006  cfgMgr->getNode(ConfigurationManager::VERSION_ALIASES_TABLE_NAME)
2007  .getChildren();
2008  std::string tableName, tableVersion;
2009  for(auto& aliasNodePair : aliasNodePairs)
2010  {
2011  tableName = aliasNodePair.second.getNode("TableName").getValueAsString();
2012  tableVersion = aliasNodePair.second.getNode("Version").getValueAsString();
2013 
2014  __COUT__ << "Table Alias: " << aliasNodePair.first << " => " << tableName
2015  << "-v" << tableVersion << "" << __E__;
2016 
2017  if(tableName == DesktopIconTable::ICON_TABLE &&
2018  TableVersion(tableVersion) == iconTable.originalVersion_)
2019  {
2020  __COUT__ << "Found alias! Changing icon table version alias."
2021  << __E__;
2022 
2023  tableAliasChange = true;
2024 
2025  tableView->setValueAsString(
2026  contextGroupMembers[DesktopIconTable::ICON_TABLE].toString(),
2027  row,
2028  tableView->findCol("Version"));
2029  }
2030  else if(tableName == DesktopIconTable::PARAMETER_TABLE &&
2031  TableVersion(tableVersion) == parameterTable.originalVersion_)
2032  {
2033  __COUT__
2034  << "Found alias! Changing icon parameter table version alias."
2035  << __E__;
2036 
2037  tableAliasChange = true;
2038 
2039  tableView->setValueAsString(
2040  contextGroupMembers[DesktopIconTable::PARAMETER_TABLE].toString(),
2041  row,
2042  tableView->findCol("Version"));
2043  }
2044 
2045  ++row;
2046  }
2047 
2048  if(tableAliasChange)
2049  {
2050  std::stringstream ss;
2051  tableView->print(ss);
2052  __COUT__ << ss.str();
2053 
2054  // save or find equivalent
2055  backboneGroupMembers[ConfigurationManager::VERSION_ALIASES_TABLE_NAME] =
2057  xmlOut,
2058  cfgMgr,
2059  table->getTableName(),
2060  originalVersion,
2061  false /*makeTemporary*/,
2062  table,
2063  temporaryVersion,
2064  false /*ignoreDuplicates*/,
2065  true /*lookForEquivalent*/);
2066 
2067  __COUT__ << "Original version is " << table->getTableName() << "-v"
2068  << originalVersion << " and new version is v"
2069  << backboneGroupMembers
2070  [ConfigurationManager::VERSION_ALIASES_TABLE_NAME]
2071  << __E__;
2072  }
2073 
2074  } // end table version alias check
2075 
2076  // if backbone modified, save group and activate it
2077  if(groupAliasChange || tableAliasChange)
2078  {
2079  for(auto& table : backboneGroupMembers)
2080  {
2081  __COUT__ << table.first << " v" << table.second << __E__;
2082  }
2083  }
2084 
2085  __COUT__ << "Checking for duplicate Backbone groups..." << __E__;
2086  TableGroupKey newBackboneKey =
2087  cfgMgr->findTableGroup(backboneGroupName, backboneGroupMembers);
2088 
2089  if(!newBackboneKey.isInvalid())
2090  {
2091  __COUT__ << "Found equivalent group key (" << newBackboneKey << ") for "
2092  << backboneGroupName << "." << __E__;
2093  xmlOut.addTextElementToData(backboneGroupName + "_foundEquivalentKey",
2094  "1" /*indicator*/);
2095  }
2096  else
2097  {
2098  newBackboneKey =
2099  cfgMgr->saveNewTableGroup(backboneGroupName, backboneGroupMembers);
2100  __COUT__ << "Saved new Backbone group key (" << newBackboneKey << ") for "
2101  << backboneGroupName << "." << __E__;
2102  }
2103 
2104  xmlOut.addTextElementToData("backboneGroupName", backboneGroupName);
2105  xmlOut.addTextElementToData("backboneGroupKey", newBackboneKey.toString());
2106 
2107  // Now need to activate Context and Backbone group
2108  __COUT__ << "Activating Context group key (" << newContextKey << ") for "
2109  << contextGroupName << "." << __E__;
2110  __COUT__ << "Activating Backbone group key (" << newBackboneKey << ") for "
2111  << backboneGroupName << "." << __E__;
2112 
2113  // acquire all active groups and ignore errors, so that activateTableGroup does not
2114  // erase other active groups
2115  cfgMgr->restoreActiveTableGroups(
2116  false /*throwErrors*/,
2117  "" /*pathToActiveGroupsFile*/,
2118  ConfigurationManager::LoadGroupType::ALL_TYPES /*onlyLoadIfBackboneOrContext*/
2119  );
2120 
2121  // activate group
2122  cfgMgr->activateTableGroup(contextGroupName, newContextKey);
2123  cfgMgr->activateTableGroup(backboneGroupName, newBackboneKey);
2124 
2125  // always add active table groups to xml response
2127  }
2128  return true;
2129 } // end handleAddDesktopIconXML()
2130 catch(std::runtime_error& e)
2131 {
2132  __SS__ << "Error adding Desktop Icon!\n\n " << e.what() << __E__;
2133  __COUT__ << "\n" << ss.str() << __E__;
2134  xmlOut.addTextElementToData("Error", ss.str());
2135  return false;
2136 }
2137 catch(...)
2138 {
2139  __SS__ << "Error adding Desktop Icon!" << __E__;
2140  try
2141  {
2142  throw;
2143  } //one more try to printout extra info
2144  catch(const std::exception& e)
2145  {
2146  ss << "Exception message: " << e.what();
2147  }
2148  catch(...)
2149  {
2150  }
2151  __COUT__ << "\n" << ss.str() << __E__;
2152  xmlOut.addTextElementToData("Error", ss.str());
2153  return false;
2154 } // end handleAddDesktopIconXML() catch
2155 
2156 //==============================================================================
2157 void ConfigurationSupervisorBase::recursiveCopyTreeUIDNode(
2158  HttpXmlDocument& xmlOut,
2159  ConfigurationManagerRW* cfgMgr,
2160  std::map<std::string /*modified table*/, TableVersion /* modified version */>&
2161  modifiedTablesMap,
2162  const unsigned int startingDepth,
2163  const unsigned int depth,
2164  const unsigned int numberOfInstances,
2165  TableView* cfgView,
2166  const std::string& uidToCopy)
2167 try
2168 {
2169  __COUTV__(startingDepth);
2170  __COUTV__(depth);
2171  __COUTV__(numberOfInstances);
2172 
2173  // throw std::runtime_error("hello");
2174 
2175  // Steps:
2176  // Assume temporary table version already created correctly for recursive level
2177  // Assume already decided it is correct to copy record at row parameter
2178  // Assume after modifications the version saving is handled above this function call
2179  // 1. copy the target row
2180  // - if depth,
2181  // 2. - check source row, for secondary copies through links
2182  // - if a link is found, check that there is not unanimous pointing by siblings
2183  // -- if unanimous pointing by siblings, do not do secondary copy, just point
2184  // 3. -- if not unanimous,
2185  // * use/create temporary version of child table
2186  // * for each instance
2187  // - recursive secondary copy (depth-1)
2188  // * save child table
2189  //
2190 
2191  // Step 1. copy the target row
2192  unsigned int col = cfgView->getColUID();
2193  unsigned int row = cfgView->findRow(col, uidToCopy);
2194 
2195  __COUT__ << "Copying " << cfgView->getTableName() << " v" << cfgView->getVersion()
2196  << " row=" << row << " record=" << uidToCopy
2197  << " instances=" << numberOfInstances << __E__;
2198 
2199  cfgView->print();
2200  // for(unsigned int i = 0; i < numberOfInstances; ++i)
2201  cfgView->copyRows(cfgMgr->getUsername(),
2202  *cfgView /*source table*/,
2203  row,
2204  1 /*srcRowsToCopy*/,
2205  -1 /*destOffsetRow*/,
2206  true /*generateUniqueDataColumns*/,
2207  uidToCopy /*baseNameAutoUID*/); // make the name similar
2208 
2209  // if no secondary copies, done now
2210  // check for secondary copies
2211  return;
2212 
2213  // secondary table copies
2214  std::string tableName = "secondary";
2215  TableVersion version(modifiedTablesMap.at(tableName));
2216 
2217  TableBase* table = cfgMgr->getTableByName(tableName);
2218  try
2219  {
2220  table->setActiveView(version);
2221  }
2222  catch(...)
2223  {
2224  if(version.isTemporaryVersion())
2225  throw; // if temporary, there is no hope to find lost version
2226 
2227  __COUT__ << "Failed to find stored version, so attempting to "
2228  "load version: "
2229  << tableName << " v" << version << __E__;
2230  cfgMgr->getVersionedTableByName(tableName, version);
2231  }
2232 
2233  __COUT__ << tableName << " active version is " << table->getViewVersion() << __E__;
2234 
2235  if(version != table->getViewVersion())
2236  {
2237  __SS__ << "Target table version (" << version
2238  << ") is not the currently active version (" << table->getViewVersion()
2239  << "). Try refreshing the tree." << __E__;
2240  __SS_THROW__;
2241  }
2242 
2243  // version handling:
2244  // always make a new temporary-version from source-version
2245  // edit temporary-version
2246  // if edit fails
2247  // delete temporary-version
2248  // else
2249  // return new temporary-version
2250  // if source-version was temporary
2251  // then delete source-version
2252  TableVersion temporaryVersion = table->createTemporaryView(version);
2253 
2254  __COUT__ << "Created temporary version " << temporaryVersion << __E__;
2255 
2256  cfgView = table->getTemporaryView(temporaryVersion);
2257  cfgView->init(); // prepare maps
2258 
2259  try // while editing
2260  {
2261  // edit...
2262 
2263  cfgView->init(); // verify new table (throws runtime_errors)
2264  }
2265  catch(...) // erase temporary view before re-throwing error
2266  {
2267  __COUT__ << "Caught error while editing. Erasing temporary version." << __E__;
2268  table->eraseView(temporaryVersion);
2269  throw;
2270  }
2271 
2273  xmlOut,
2274  cfgMgr,
2275  tableName,
2276  version,
2277  true /*make temporary*/,
2278  table,
2279  temporaryVersion,
2280  true /*ignoreDuplicates*/); // save temporary version properly
2281 }
2282 catch(std::runtime_error& e)
2283 {
2284  __SS__ << ("Error copying tree target '" + uidToCopy + "' at depth " +
2285  std::to_string(startingDepth - depth) + " in table '" +
2286  cfgView->getTableName() + ".' " + std::string(e.what()))
2287  << __E__;
2288  __COUT__ << "\n" << ss.str() << __E__;
2289  xmlOut.addTextElementToData("Error", ss.str());
2290 }
2291 catch(...)
2292 {
2293  __SS__ << ("Error copying tree target '" + uidToCopy + "' at depth " +
2294  std::to_string(startingDepth - depth) + " in table '" +
2295  cfgView->getTableName() + ".' ")
2296  << __E__;
2297  try
2298  {
2299  throw;
2300  } //one more try to printout extra info
2301  catch(const std::exception& e)
2302  {
2303  ss << "Exception message: " << e.what();
2304  }
2305  catch(...)
2306  {
2307  }
2308  __COUT__ << "\n" << ss.str() << __E__;
2309  xmlOut.addTextElementToData("Error", ss.str());
2310 } // 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"
void activateTableGroup(const std::string &tableGroupName, TableGroupKey tableGroupKey, std::string *accumulatedTreeErrors=0, std::string *groupTypeString=0)
modifiers of table groups
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
void eraseTemporaryVersion(const std::string &tableName, TableVersion targetVersion=TableVersion())
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
const std::string & getTableName(void) const
Getters.
Definition: TableBase.cc:814
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)
TableBase * table_
everything needed for editing a table
bool createdTemporaryVersion_
indicates if temp version was created here