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