otsdaq  3.06.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  if(accumulatedWarnings.size())
365  __COUT_WARN__ << "Ignoring these errors: " << accumulatedWarnings << __E__;
366 
367  // cfgMgr->loadConfigurationBackbone(); //already loaded by initializeActiveGroups of getAllTableInfo
368 
369  __COUTT__ << "handleCreateTableGroupXML loaded runtime=" << cfgMgr->runTimeSeconds()
370  << __E__;
371 
372  std::map<std::string /*tableName*/,
373  std::map<std::string /*aliasName*/, TableVersion /*version*/>>
374  versionAliases = cfgMgr->getVersionAliases();
375  // for(const auto& aliases : versionAliases)
376  // for(const auto& alias : aliases.second)
377  // __COUT__ << aliases.first << " " << alias.first << " " << alias.second
378  // << __E__;
379 
380  std::map<std::string /*name*/, TableVersion /*version*/> groupMembers;
381  std::map<std::string /*name*/, std::string /*alias*/> memberTableAliases;
382 
383  std::string name, versionStr, alias;
384  TableVersion version;
385  auto c = tableList.find(',', 0);
386  auto i = c;
387  i = 0; // auto used to get proper index/length type
388  while(c < tableList.length())
389  {
390  // add the table and version pair to the map
391  name = tableList.substr(i, c - i);
392  i = c + 1;
393  c = tableList.find(',', i);
394  if(c == std::string::npos) // missing version list entry?!
395  {
396  __SS__ << "Incomplete Table Name-Version pair!" << __E__;
397  __COUT_ERR__ << "\n" << ss.str();
398  xmlOut.addTextElementToData("Error", ss.str());
399  return;
400  }
401 
402  versionStr = tableList.substr(i, c - i);
403  i = c + 1;
404  c = tableList.find(',', i);
405 
406  //__COUT__ << "name: " << name << __E__;
407  //__COUT__ << "versionStr: " << versionStr << __E__;
408 
409  // check if version is an alias and convert
410  if(versionStr.find(ConfigurationManager::ALIAS_VERSION_PREAMBLE) == 0)
411  {
412  alias =
413  versionStr.substr(ConfigurationManager::ALIAS_VERSION_PREAMBLE.size());
414 
415  __COUT__ << "Found alias " << name << " " << versionStr << __E__;
416 
417  // convert alias to version
418  if(versionAliases.find(name) != versionAliases.end() &&
419  versionAliases[name].find(alias) != versionAliases[name].end())
420  {
421  version = versionAliases[name][alias];
422  __COUT__ << name << " version alias '" << alias
423  << "'translated to: " << version << __E__;
424 
425  memberTableAliases[name] = alias;
426  }
427  else
428  {
429  __SS__ << "version alias '"
430  << versionStr.substr(
431  ConfigurationManager::ALIAS_VERSION_PREAMBLE.size())
432  << "' was not found in active version aliases! Please check your "
433  "active backbone!"
434  << __E__;
435  __COUT_ERR__ << "\n" << ss.str();
436  xmlOut.addTextElementToData("Error", ss.str());
437  return;
438  }
439  }
440  else
441  version = TableVersion(versionStr);
442 
443  if(version.isTemporaryVersion())
444  {
445  __SS__ << "Groups can not be created using temporary member tables. "
446  << "Table member '" << name << "' with temporary version '" << version
447  << "' is illegal." << __E__;
448  xmlOut.addTextElementToData("Error", ss.str());
449  return;
450  }
451 
452  // enforce that table exists
453  if(allTableInfo.find(name) == allTableInfo.end())
454  {
455  __SS__ << "Groups can not be created using mock-up member tables of "
456  "undefined tables. "
457  << "Table member '" << name << "' is not defined." << __E__;
458  xmlOut.addTextElementToData("Error", ss.str());
459  return;
460  }
461 
462  if(version.isMockupVersion())
463  {
464  // if mockup, then generate a new persistent version to use based on mockup
465  TableBase* table = cfgMgr->getTableByName(name);
466  // create a temporary version from the mockup as source version
467  TableVersion temporaryVersion = table->createTemporaryView();
468  __COUT__ << "\t\ttemporaryVersion: " << temporaryVersion << __E__;
469 
470  // if other versions exist check for another mockup, and use that instead
471  __COUT__ << "Creating version from mock-up for name: " << name
472  << " inputVersionStr: " << versionStr << __E__;
473 
474  // set table comment
475  table->getTemporaryView(temporaryVersion)
476  ->setComment("Auto-generated from mock-up.");
477 
478  // finish off the version creation
480  xmlOut,
481  cfgMgr,
482  name,
483  TableVersion() /*original source is mockup*/,
484  false /* makeTemporary */,
485  table,
486  temporaryVersion /*temporary modified version*/,
487  false /*ignore duplicates*/,
488  true /*look for equivalent*/);
489 
490  __COUT__ << "Using mockup version: " << version << __E__;
491  }
492 
493  //__COUT__ << "version: " << version << __E__;
494  groupMembers[name] = version;
495  } // end member verification loop
496 
497  __COUTT__ << "handleCreateTableGroupXML tables saved runtime="
498  << cfgMgr->runTimeSeconds() << __E__;
499 
500  __COUTV__(StringMacros::mapToString(memberTableAliases));
501 
502  if(!allowDuplicates)
503  {
504  __COUT__ << "Checking for duplicate groups..." << __E__;
505  try
506  {
507  TableGroupKey foundKey =
508  cfgMgr->findTableGroup(groupName, groupMembers, memberTableAliases);
509  __COUTT__ << "handleCreateTableGroupXML group duplicates checked runtime="
510  << cfgMgr->runTimeSeconds() << __E__;
511  if(!foundKey.isInvalid())
512  {
513  // return found equivalent key
514  xmlOut.addTextElementToData("TableGroupName", groupName);
515  xmlOut.addTextElementToData("TableGroupKey", foundKey.toString());
516 
517  if(lookForEquivalent)
518  {
519  __COUT__ << "Found equivalent group key (" << foundKey << ") for "
520  << groupName << "." << __E__;
521  // allow this equivalent group to be the response without an error
522  xmlOut.addTextElementToData("foundEquivalentKey", "1"); // indicator
523 
524  // insert get table info
525  handleGetTableGroupXML(xmlOut,
526  cfgMgr,
527  groupName,
528  foundKey,
529  ignoreWarnings,
530  true /* cacheOnly */);
531  return;
532  }
533  else // treat as error, if not looking for equivalent
534  {
535  __COUT__ << "Treating duplicate group as error." << __E__;
536  __SS__ << ("Failed to create table group: " + groupName +
537  ". It is a duplicate of an existing group key (" +
538  foundKey.toString() + ")");
539  __COUT_ERR__ << ss.str() << __E__;
540  xmlOut.addTextElementToData("Error", ss.str());
541  return;
542  }
543  }
544 
545  __COUT__ << "Check for duplicate groups complete." << __E__;
546  }
547  catch(...)
548  {
549  __COUT_WARN__ << "Ignoring errors looking for duplicate groups! Proceeding "
550  "with new group creation."
551  << __E__;
552  }
553  }
554 
555  // check the group for errors before creating group
556  try
557  {
558  cfgMgr->loadMemberMap(groupMembers);
559 
560  std::string accumulateErrors = "";
561  for(auto& groupMemberPair : groupMembers)
562  {
563  TableView* cfgViewPtr =
564  cfgMgr->getTableByName(groupMemberPair.first)->getViewP();
565  if(cfgViewPtr->getDataColumnSize() != cfgViewPtr->getNumberOfColumns() ||
566  cfgViewPtr->getSourceColumnMismatch() !=
567  0) // check for column size mismatch
568  {
569  // const std::set<std::string> srcColNames = cfgViewPtr->getSourceColumnNames();
570  __SS__ << "\n\nThere were errors found in loading a member table "
571  << groupMemberPair.first << ":v" << cfgViewPtr->getVersion()
572  << ". Please see the details below:\n\n"
573  << cfgViewPtr->getMismatchColumnInfo();
574 
575  __COUT_ERR__ << "\n" << ss.str();
576  xmlOut.addTextElementToData("Error", ss.str());
577  return;
578  }
579  }
580  }
581  catch(std::runtime_error& e)
582  {
583  __SS__ << "Failed to create table group: " << groupName
584  << ".\nThere were problems loading the chosen members:\n\n"
585  << e.what() << __E__;
586  __COUT_ERR__ << "\n" << ss.str();
587  xmlOut.addTextElementToData("Error", ss.str());
588  return;
589  }
590  catch(...)
591  {
592  __SS__ << "Failed to create table group: " << groupName << __E__;
593  try
594  {
595  throw;
596  } //one more try to printout extra info
597  catch(const std::exception& e)
598  {
599  ss << "Exception message: " << e.what();
600  }
601  catch(...)
602  {
603  }
604  __COUT_ERR__ << "\n" << ss.str();
605  xmlOut.addTextElementToData("Error", ss.str());
606  return;
607  }
608 
609  __COUTT__ << "handleCreateTableGroupXML group members init checked runtime="
610  << cfgMgr->runTimeSeconds() << __E__;
611 
612  // check the tree for warnings before creating group
613  std::string accumulateTreeErrs;
614  cfgMgr->getChildren(&groupMembers, &accumulateTreeErrs);
615  if(accumulateTreeErrs != "")
616  {
617  __COUT_WARN__ << "\n" << accumulateTreeErrs << __E__;
618  if(!ignoreWarnings)
619  {
620  xmlOut.addTextElementToData("TreeErrors", accumulateTreeErrs);
621  return;
622  }
623  }
624 
625  __COUTT__ << "handleCreateTableGroupXML tree checked runtime="
626  << cfgMgr->runTimeSeconds() << __E__;
627 
628  TableGroupKey newKey;
629  try
630  {
631  __COUT__ << "Saving new group..." << __E__;
632  newKey = cfgMgr->saveNewTableGroup(
633  groupName, groupMembers, groupComment, &memberTableAliases);
634  }
635  catch(std::runtime_error& e)
636  {
637  __SS__ << "Failed to create table group: " << groupName << __E__;
638  ss << "\n\n" << e.what() << __E__;
639  __COUT_ERR__ << ss.str();
640  xmlOut.addTextElementToData("Error", ss.str());
641  return;
642  }
643  catch(...)
644  {
645  __SS__ << "Failed to create table group: " << groupName << __E__;
646  try
647  {
648  throw;
649  } //one more try to printout extra info
650  catch(const std::exception& e)
651  {
652  ss << "Exception message: " << e.what();
653  }
654  catch(...)
655  {
656  }
657  __COUT_ERR__ << ss.str();
658  xmlOut.addTextElementToData("Error", ss.str());
659  return;
660  }
661 
662  __COUTT__ << "handleCreateTableGroupXML group saved runtime="
663  << cfgMgr->runTimeSeconds() << __E__;
664 
665  // insert get table info
666  __COUT__ << "Loading new table group..." << __E__;
668  xmlOut, cfgMgr, groupName, newKey, ignoreWarnings, true /* cacheOnly */);
669 
670  __COUTT__ << "handleCreateTableGroupXML end runtime=" << cfgMgr->runTimeSeconds()
671  << __E__;
672 
673 } // end handleCreateTableGroupXML()
674 catch(std::runtime_error& e)
675 {
676  __SS__ << "Error saving table group!\n\n " << e.what() << __E__;
677  __COUT_ERR__ << "\n" << ss.str() << __E__;
678  xmlOut.addTextElementToData("Error", ss.str());
679 }
680 catch(...)
681 {
682  __SS__ << "Error saving table group!" << __E__;
683  try
684  {
685  throw;
686  } //one more try to printout extra info
687  catch(const std::exception& e)
688  {
689  ss << "Exception message: " << e.what();
690  }
691  catch(...)
692  {
693  }
694  __COUT_ERR__ << "\n" << ss.str() << __E__;
695  xmlOut.addTextElementToData("Error", ss.str());
696 } // end handleCreateTableGroupXML() catch
697 
698 //==============================================================================
724  HttpXmlDocument& xmlOut,
725  ConfigurationManagerRW* cfgMgr,
726  const std::string& groupName,
727  TableGroupKey groupKey,
728  bool ignoreWarnings /* = false */,
729  bool cacheOnly /* = false */)
730 try
731 {
732  // char tmpIntStr[100];
733  xercesc::DOMElement *parentEl, *configEl;
734 
735  // steps:
736  // if invalid key, get latest key
737  // get specific group with key
738  // give member names and versions
739  // get all table groups to locate historical keys
740  // get all groups to find historical keys
741 
742  // std::set<std::string /*name+version*/> allGroups =
743  // cfgMgr->getConfigurationInterface()->getAllTableGroupNames(groupName);
744  // std::string name;
745  // TableGroupKey key;
746  // //put them in a set to sort them as TableGroupKey defines for operator<
747  // std::set<TableGroupKey> sortedKeys;
748  // for(auto& group: allGroups)
749  // {
750  // //now uses database filter
751  // TableGroupKey::getGroupNameAndKey(group,name,key);
752  // //if(name == groupName)
753  // sortedKeys.emplace(key);
754  // }
755 
756  __COUTTV__(cacheOnly);
757 
758  //======
760  auto SpanToXML = [](auto const& sortedKeys, auto& xmlOut) {
761  //add lo and hi spans, instead of each individual value
762  size_t lo = -1, hi = -1;
763  for(auto& keyInOrder : sortedKeys)
764  {
765  if(lo == size_t(-1)) //establish start of potential span
766  {
767  hi = lo = keyInOrder.key();
768  continue;
769  }
770  else if(hi + 1 == keyInOrder.key()) //span is growing
771  {
772  hi = keyInOrder.key();
773  continue;
774  }
775  //else jump by more than one, so close out span
776 
777  if(lo == hi) //single value
778  xmlOut.addNumberElementToData("HistoricalTableGroupKey", lo);
779  else //span
780  xmlOut.addTextElementToData(
781  "HistoricalTableGroupKey",
782  "_" + std::to_string(lo) + "_" + std::to_string(hi));
783  hi = lo = keyInOrder.key();
784  }
785 
786  if(lo != size_t(-1)) //check if last one to do!
787  {
788  if(lo == hi) //single value
789  xmlOut.addNumberElementToData("HistoricalTableGroupKey", lo);
790  else //span
791  xmlOut.addTextElementToData(
792  "HistoricalTableGroupKey",
793  "_" + std::to_string(lo) + "_" + std::to_string(hi));
794  }
795  }; //end local lambda SpanToXML()
796  auto vSpanToXML = [](auto const& sortedKeys, auto& xmlOut, auto& configEl) {
797  //add lo and hi spans, instead of each individual value
798  size_t lo = -1, hi = -1;
799  for(auto& keyInOrder : sortedKeys)
800  {
801  if(lo == size_t(-1)) //establish start of potential span
802  {
803  hi = lo = keyInOrder.version();
804  continue;
805  }
806  else if(hi + 1 == keyInOrder.version()) //span is growing
807  {
808  hi = keyInOrder.version();
809  continue;
810  }
811  //else jump by more than one, so close out span
812 
813  if(lo == hi) //single value
814  xmlOut.addNumberElementToParent("TableExistingVersion", lo, configEl);
815  else //span
816  xmlOut.addTextElementToParent(
817  "TableExistingVersion",
818  "_" + std::to_string(lo) + "_" + std::to_string(hi),
819  configEl);
820  hi = lo = keyInOrder.version();
821  }
822 
823  if(lo != size_t(-1)) //check if last one to do!
824  {
825  if(lo == hi) //single value
826  xmlOut.addNumberElementToParent("TableExistingVersion", lo, configEl);
827  else //span
828  xmlOut.addTextElementToParent(
829  "TableExistingVersion",
830  "_" + std::to_string(lo) + "_" + std::to_string(hi),
831  configEl);
832  }
833  }; //end local lambda vSpanToXML()
834 
835  {
836  const GroupInfo& groupInfo =
837  cfgMgr->getGroupInfo(groupName, !cacheOnly /* attemptToReloadKeys */);
838  const std::set<TableGroupKey>& sortedKeys = groupInfo.getKeys(); // rename
839 
840  __COUTT__ << groupName << " keys: " << StringMacros::setToString(sortedKeys)
841  << __E__;
842  __COUTT__ << "Active groups: "
843  << StringMacros::mapToString(cfgMgr->getActiveTableGroups()) << __E__;
844  __COUTT__ << "Active tables: "
845  << StringMacros::mapToString(cfgMgr->getActiveVersions()) << __E__;
846 
847  if(!cacheOnly &&
848  (groupKey
849  .isInvalid() || // if invalid or not found, likely key info not loaded, so get latest
850  sortedKeys.find(groupKey) == sortedKeys.end() ||
851  sortedKeys.size() < 2))
852  {
853  // report error if group key not found
854  if(!groupKey.isInvalid() || sortedKeys.size() == 0)
855  {
856  // attempt to reload all group info and power through
857  std::string accumulatedWarnings;
858  __COUTT__ << "Attempting full table refresh (assuming cache not yet "
859  "established)."
860  << __E__;
861  /*const std::map<std::string, TableInfo>& allTableInfo = */ cfgMgr
862  ->getAllTableInfo(true /* refresh */,
863  &accumulatedWarnings,
864  "" /* errorFilterName */,
865  true /* getGroupKeys*/,
866  false /* getGroupInfo */,
867  true /* initializeActiveGroups */);
868  __COUTT__ << "After full table refresh (assuming cache not yet "
869  "established) so ignoring these errors: "
870  << accumulatedWarnings << __E__;
871 
872  // xmlOut.addTextElementToData("Error", ss.str());
873 
874  const GroupInfo& groupInfo2 = cfgMgr->getGroupInfo(groupName);
875  const std::set<TableGroupKey>& sortedKeys2 =
876  groupInfo2.getKeys(); // rename
877 
878  if(sortedKeys2.find(groupKey) == sortedKeys2.end())
879  {
880  __SS__ << "Group key " << groupKey << " was not found for group '"
881  << groupName << "!'" << __E__;
882  ss << "Her are the found " << sortedKeys2.size() << " '" << groupName
883  << "' keys: " << __E__;
884  for(auto& keyInOrder : sortedKeys2)
885  ss << "\t" << keyInOrder << __E__;
886  __COUT_WARN__ << "\n" << ss.str() << __E__;
887  }
888  SpanToXML(sortedKeys2, xmlOut);
889  }
890  else
891  {
892  if(sortedKeys.size())
893  groupKey = *sortedKeys.rbegin();
894  __COUT_WARN__
895  << "Group key requested was invalid or not found, going with latest "
896  << groupKey << __E__;
897 
898  // add all other sorted keys for this groupName
899  SpanToXML(sortedKeys, xmlOut);
900  }
901  }
902  else
903  {
904  // add all other sorted keys for this groupName
905  SpanToXML(sortedKeys, xmlOut);
906  }
907 
908  if(cfgMgr->getActiveVersions().size() == 0)
909  {
910  __COUTT__
911  << "There are no active tables. Attempting to initialize active groups."
912  << __E__;
913  //if no active tables, attempt to init active groups (it should prevent confusing warnings to users complaining about a partially loaded configuration)
914  std::string tmpAccumulateWarnings;
915  cfgMgr->init(0 /*accumulatedErrors*/,
916  false /*initForWriteAccess*/,
917  &tmpAccumulateWarnings);
918  __COUTT__ << "Now Active tables: "
919  << StringMacros::mapToString(cfgMgr->getActiveVersions()) << __E__;
920  __COUTT__ << "Ingoring warnings during init of active groups: "
921  << tmpAccumulateWarnings << __E__;
922  }
923  }
924 
925  xmlOut.addTextElementToData("TableGroupName", groupName);
926  xmlOut.addTextElementToData("TableGroupKey", groupKey.toString());
927 
928  parentEl = xmlOut.addTextElementToData("TableGroupMembers", "");
929 
930  // get specific group with key
931  std::map<std::string /*name*/, TableVersion /*version*/> memberMap;
932  std::map<std::string /*name*/, std::string /*alias*/> groupMemberAliases;
933 
934  __COUT__ << "groupName=" << groupName << __E__;
935  __COUT__ << "groupKey=" << groupKey << __E__;
936 
937  const std::map<std::string, TableInfo>& allTableInfo = cfgMgr->getAllTableInfo();
938  std::map<std::string, TableInfo>::const_iterator it;
939 
940  // load group so comments can be had
941  // and also group metadata (author, comment, createTime)
942  try
943  {
944  std::string groupAuthor, groupComment, groupCreationTime, groupTypeString;
945  std::string accumulateTreeErrors;
946 
947  __COUTV__(ignoreWarnings);
948  cfgMgr->loadTableGroup(groupName,
949  groupKey,
950  false /*doActivate*/,
951  &memberMap,
952  0 /*progressBar*/,
953  ignoreWarnings ? 0 : /*accumulateTreeErrors*/
954  &accumulateTreeErrors,
955  &groupComment,
956  &groupAuthor,
957  &groupCreationTime,
958  false /*doNotLoadMember*/,
959  &groupTypeString,
960  &groupMemberAliases);
961 
962  if(accumulateTreeErrors != "")
963  {
964  __COUTV__(accumulateTreeErrors);
965  xmlOut.addTextElementToData("TreeErrors", accumulateTreeErrors);
966  }
967 
968  xmlOut.addTextElementToData("TableGroupAuthor", groupAuthor);
969  xmlOut.addTextElementToData("TableGroupComment", groupComment);
970  xmlOut.addTextElementToData("TableGroupCreationTime", groupCreationTime);
971  xmlOut.addTextElementToData("TableGroupType", groupTypeString);
972  }
973  catch(const std::runtime_error& e)
974  {
975  __SS__ << "Table group \"" + groupName + "(" + groupKey.toString() + ")" +
976  "\" members can not be loaded!\n\n" + e.what()
977  << __E__;
978  __COUT_ERR__ << ss.str();
979  xmlOut.addTextElementToData("Error", ss.str());
980  // return;
981  }
982  catch(...)
983  {
984  __SS__ << "Table group \"" + groupName + "(" + groupKey.toString() + ")" +
985  "\" members can not be loaded!"
986  << __E__;
987  try
988  {
989  throw;
990  } //one more try to printout extra info
991  catch(const std::exception& e)
992  {
993  ss << "Exception message: " << e.what();
994  }
995  catch(...)
996  {
997  }
998  __COUT_ERR__ << ss.str();
999  xmlOut.addTextElementToData("Error", ss.str());
1000  // return;
1001  }
1002 
1003  __COUTV__(StringMacros::mapToString(groupMemberAliases));
1004 
1005  std::map<std::string /*table name*/,
1006  std::map<std::string /*version alias*/, TableVersion /*aliased version*/>>
1007  versionAliases = cfgMgr->getVersionAliases();
1008 
1009  __COUT__ << "# of table version aliases: " << versionAliases.size() << __E__;
1010 
1011  // Seperate loop to get name and version
1012  for(auto& memberPair : memberMap)
1013  {
1014  xmlOut.addTextElementToParent("MemberName", memberPair.first, parentEl);
1015 
1016  // if member is in groupMemberAliases, then alias version
1017  if(groupMemberAliases.find(memberPair.first) != groupMemberAliases.end())
1018  {
1019  configEl = xmlOut.addTextElementToParent(
1020  "MemberVersion",
1021  ConfigurationManager::ALIAS_VERSION_PREAMBLE +
1022  groupMemberAliases[memberPair.first], // return the ALIAS:<alias>
1023  parentEl);
1024  //also include actual version for reference
1025  xmlOut.addTextElementToParent(
1026  "ProvenanceMemberVersion", memberPair.second.toString(), configEl);
1027  // AND warn if actual version mismatches current alias!!
1028  // if no current backbone alias for this member, or alias version does not match member version
1029  auto vit = versionAliases.find(memberPair.first);
1030  if(vit == versionAliases.end() || //tableName is not in backbone aliases
1031  vit->second.find(groupMemberAliases[memberPair.first]) ==
1032  vit->second.end() || //alias is not in backbone aliases for this table
1033  vit->second[groupMemberAliases[memberPair.first]] !=
1034  memberPair
1035  .second) //backbone's alias version does not match provenance member version
1036  {
1037  __SS__ << "Warning: Version alias mismatch with active Backbone! <b>\"" +
1038  groupName + "(" + groupKey.toString() + ")" +
1039  "\"</b> group member table <b>'"
1040  << memberPair.first << "'</b> is using version alias <b>'"
1041  << groupMemberAliases[memberPair.first] << "'</b>";
1042  if(vit == versionAliases.end() || //tableName is not in backbone aliases
1043  vit->second.find(groupMemberAliases[memberPair.first]) ==
1044  vit->second.end())
1045  {
1046  ss << " which no longer has a valid translation in the active "
1047  "Backbone! "
1048  << " The original provenance version is <b>" << memberPair.first
1049  << "-v" << memberPair.second
1050  << "</b>.\n\nPlease consider whether this is an issue, or if you "
1051  "should first recreate this group with updated Backbone table "
1052  "alias translations before activating.";
1053 
1054  //also flag that active backbone translation is invalid
1055  xmlOut.addTextElementToParent("ActiveBackboneAliasVersion",
1056  TableVersion().toString() /* invalid*/,
1057  configEl);
1058  }
1059  else
1060  {
1061  ss << " which translates to <b>" << memberPair.first << "-v"
1062  << vit->second[groupMemberAliases[memberPair.first]]
1063  << "</b> with current active Backbone group."
1064  << " There is a mismatch with the original provenance version of "
1065  "<b>"
1066  << memberPair.first << "-v" << memberPair.second
1067  << "</b>.\n\nPlease consider whether this is an issue, or if you "
1068  "should first recreate this group with updated Backbone table "
1069  "alias translations before activating."
1070  << __E__;
1071 
1072  //also include mismatching active backone translation
1073  xmlOut.addTextElementToParent(
1074  "ActiveBackboneAliasVersion",
1075  vit->second[groupMemberAliases[memberPair.first]].toString(),
1076  configEl);
1077  }
1078  __COUT_WARN__ << "\n" << ss.str() << __E__;
1079  xmlOut.addTextElementToData("Warning", ss.str());
1080  } //end alias warning handling
1081  else
1082  {
1083  __COUT__ << "\"" + groupName + "(" + groupKey.toString() + ")" +
1084  "\" group member table '"
1085  << memberPair.first << "' is using version alias '"
1086  << groupMemberAliases[memberPair.first]
1087  << "' which currently matches the active Backbone translation "
1088  "version v"
1089  << memberPair.second << " = v"
1090  << vit->second[groupMemberAliases[memberPair.first]] << __E__;
1091  }
1092  }
1093  else
1094  configEl = xmlOut.addTextElementToParent(
1095  "MemberVersion", memberPair.second.toString(), parentEl);
1096 
1097  it = allTableInfo.find(memberPair.first);
1098  if(it == allTableInfo.end())
1099  {
1100  if(!cacheOnly) //only an 'error' if not cacheOnly
1101  xmlOut.addTextElementToData(
1102  "Error", "Table \"" + memberPair.first + "\" can not be retrieved!");
1103  continue;
1104  }
1105 
1106  xmlOut.addTextElementToParent(
1107  "MemberComment", it->second.tablePtr_->getView().getComment(), parentEl);
1108 
1109  if(versionAliases.find(it->first) != versionAliases.end())
1110  for(auto& aliasVersion : versionAliases[it->first])
1111  xmlOut.addTextElementToParent(
1112  "TableExistingVersion",
1113  ConfigurationManager::ALIAS_VERSION_PREAMBLE + aliasVersion.first,
1114  configEl);
1115 
1116  vSpanToXML(it->second.versions_, xmlOut, configEl);
1117  } //end member map loop
1118 
1119 } // end handleGetTableGroupXML()
1120 catch(std::runtime_error& e)
1121 {
1122  __SS__ << ("Error getting table group!\n\n" + std::string(e.what())) << __E__;
1123  __COUT_ERR__ << "\n" << ss.str();
1124  xmlOut.addTextElementToData("Error", ss.str());
1125 }
1126 catch(...)
1127 {
1128  __SS__ << ("Error getting table group!\n\n") << __E__;
1129  try
1130  {
1131  throw;
1132  } //one more try to printout extra info
1133  catch(const std::exception& e)
1134  {
1135  ss << "Exception message: " << e.what();
1136  }
1137  catch(...)
1138  {
1139  }
1140  __COUT_ERR__ << "\n" << ss.str();
1141  xmlOut.addTextElementToData("Error", ss.str());
1142 } // end handleGetTableGroupXML() catch
1143 
1144 //==============================================================================
1145 bool ConfigurationSupervisorBase::handleAddDesktopIconXML(
1146  HttpXmlDocument& xmlOut,
1147  ConfigurationManagerRW* cfgMgr,
1148  const std::string& iconCaption,
1149  const std::string& iconAltText,
1150  const std::string& iconFolderPath,
1151  const std::string& iconImageURL,
1152  const std::string& iconWindowURL,
1153  const std::string& iconPermissions,
1154  std::string windowLinkedApp /*= ""*/,
1155  unsigned int windowLinkedAppLID /*= 0*/,
1156  bool enforceOneWindowInstance /*= false*/,
1157  const std::string& windowParameters /*= ""*/)
1158 try
1159 {
1160  cfgMgr->getAllTableInfo(true /* refresh */);
1161 
1162  const std::string& author = cfgMgr->getUsername();
1163 
1164  __COUTV__(author);
1165  __COUTV__(iconCaption);
1166  __COUTV__(iconAltText);
1167  __COUTV__(iconFolderPath);
1168  __COUTV__(iconImageURL);
1169  __COUTV__(iconWindowURL);
1170  __COUTV__(iconPermissions);
1171  __COUTV__(windowLinkedApp);
1172  __COUTV__(windowLinkedAppLID);
1173  __COUTV__(enforceOneWindowInstance);
1174 
1175  __COUTV__(windowParameters); // map: CSV list
1176 
1177  // steps:
1178  // activate active context
1179  // modify desktop table and desktop parameters table
1180  // save, activate, and modify alias
1181  // just to match syntax in ConfiguratGUI
1182  // tmpCfgMgr.activateTableGroup(
1183  // tmpCfgMgr.getActiveGroupName(ConfigurationManager::GROUP_TYPE_NAME_CONTEXT),
1184  // tmpCfgMgr.getActiveGroupKey(ConfigurationManager::GROUP_TYPE_NAME_CONTEXT)
1185  // );
1186 
1187  cfgMgr->restoreActiveTableGroups(
1188  true /*throwErrors*/,
1189  "" /*pathToActiveGroupsFile*/,
1190  ConfigurationManager::LoadGroupType::
1191  ONLY_BACKBONE_OR_CONTEXT_TYPES /*onlyLoadIfBackboneOrContext*/
1192  );
1193 
1194  const std::string backboneGroupName =
1195  cfgMgr->getActiveGroupName(ConfigurationManager::GroupType::BACKBONE_TYPE);
1196 
1197  GroupEditStruct contextGroupEdit(ConfigurationManager::GroupType::CONTEXT_TYPE,
1198  cfgMgr);
1199 
1200  // Steps:
1201  // - Create record in DesktopIconTable
1202  // - Create parameter records in DesktopWindowParameterTable
1203  // - Create new Context group
1204  // - Update Aliases from old Context group to new Context group
1205  // - Activate new group
1206 
1207  TableEditStruct& iconTable = contextGroupEdit.getTableEditStruct(
1208  DesktopIconTable::ICON_TABLE, true /*markModified*/);
1209  TableEditStruct& parameterTable = contextGroupEdit.getTableEditStruct(
1210  DesktopIconTable::PARAMETER_TABLE, true /*markModified*/);
1211  TableEditStruct& appTable = contextGroupEdit.getTableEditStruct(
1212  ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME);
1213 
1214  // Create record in DesktopIconTable
1215  try
1216  {
1217  unsigned int row;
1218  std::string iconUID = "";
1219  std::string decodedCaption = StringMacros::decodeURIComponent(iconCaption);
1220 
1221  for(unsigned int i = 0; i < decodedCaption.size(); ++i)
1222  if((decodedCaption[i] >= 'a' && decodedCaption[i] <= 'z') ||
1223  (decodedCaption[i] >= 'A' && decodedCaption[i] <= 'Z') ||
1224  (decodedCaption[i] >= '0' && decodedCaption[i] <= '9'))
1225  iconUID += decodedCaption[i];
1226 
1227  // create icon record
1228  row = iconTable.tableView_->addRow(
1229  author, true /*incrementUniqueData*/, "generatedIcon" + iconUID);
1230  iconUID =
1231  iconTable.tableView_->getDataView()[row][iconTable.tableView_->getColUID()];
1232 
1233  __COUTV__(row);
1234  __COUTV__(iconUID);
1235 
1236  // set icon status true
1237  iconTable.tableView_->setValueAsString(
1238  "1", row, iconTable.tableView_->getColStatus());
1239 
1240  // set caption value
1241  iconTable.tableView_->setURIEncodedValue(
1242  iconCaption,
1243  row,
1244  iconTable.tableView_->findCol(DesktopIconTable::COL_CAPTION));
1245  // set alt text value
1246  iconTable.tableView_->setURIEncodedValue(
1247  iconAltText,
1248  row,
1249  iconTable.tableView_->findCol(DesktopIconTable::COL_ALTERNATE_TEXT));
1250  // set force one instance value
1251  iconTable.tableView_->setValueAsString(
1252  enforceOneWindowInstance ? "1" : "0",
1253  row,
1254  iconTable.tableView_->findCol(DesktopIconTable::COL_FORCE_ONLY_ONE_INSTANCE));
1255  // set permissions value
1256  iconTable.tableView_->setURIEncodedValue(
1257  iconPermissions,
1258  row,
1259  iconTable.tableView_->findCol(DesktopIconTable::COL_PERMISSIONS));
1260  // set image URL value
1261  iconTable.tableView_->setURIEncodedValue(
1262  iconImageURL,
1263  row,
1264  iconTable.tableView_->findCol(DesktopIconTable::COL_IMAGE_URL));
1265  // set window URL value
1266  iconTable.tableView_->setURIEncodedValue(
1267  iconWindowURL,
1268  row,
1269  iconTable.tableView_->findCol(DesktopIconTable::COL_WINDOW_CONTENT_URL));
1270  // set folder value
1271  iconTable.tableView_->setURIEncodedValue(
1272  iconFolderPath,
1273  row,
1274  iconTable.tableView_->findCol(DesktopIconTable::COL_FOLDER_PATH));
1275 
1276  // create link to icon app
1277  if(windowLinkedAppLID > 0)
1278  {
1279  __COUTV__(windowLinkedAppLID);
1280 
1281  int appRow = appTable.tableView_->findRow(
1282  appTable.tableView_->findCol(XDAQContextTable::colApplication_.colId_),
1283  windowLinkedAppLID);
1284  windowLinkedApp =
1285  appTable.tableView_
1286  ->getDataView()[appRow][appTable.tableView_->getColUID()];
1287  __COUT__ << "Found app by LID: " << windowLinkedApp << __E__;
1288  } // end linked app LID handling
1289 
1290  if(windowLinkedApp != "" && windowLinkedApp != "undefined" &&
1291  windowLinkedApp != TableViewColumnInfo::DATATYPE_STRING_DEFAULT)
1292  {
1293  // first check that UID exists
1294  // if not, interpret as app class type and
1295  // check for unique 'enabled' app with class type
1296  __COUTV__(windowLinkedApp);
1297 
1298  if(!windowLinkedAppLID) // no need to check if LID lookup happened already
1299  {
1300  try
1301  {
1302  windowLinkedApp = StringMacros::decodeURIComponent(windowLinkedApp);
1303  /* int appRow = */ appTable.tableView_->findRow(
1304  appTable.tableView_->getColUID(), windowLinkedApp);
1305  }
1306  catch(const std::runtime_error& e)
1307  {
1308  // attempt to treat like class, and take first match
1309  try
1310  {
1311  int appRow = appTable.tableView_->findRow(
1312  appTable.tableView_->findCol(
1313  XDAQContextTable::colApplication_.colClass_),
1314  windowLinkedApp);
1315  windowLinkedApp =
1316  appTable.tableView_
1317  ->getDataView()[appRow][appTable.tableView_->getColUID()];
1318  }
1319  catch(...)
1320  {
1321  // failed to treat like class, so throw original
1322  __SS__
1323  << "Failed to create an icon linking to XDAQ Supervisor app '"
1324  << windowLinkedApp
1325  << ".' Please make sure the Supervisor exists in the "
1326  << ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME
1327  << " table. "
1328  << "\n\nThe following error occurred: " << e.what() << __E__;
1329  appTable.tableView_->print(ss);
1330  __SS_THROW__;
1331  }
1332  }
1333  }
1334  __COUTV__(windowLinkedApp);
1335 
1336  iconTable.tableView_->setValueAsString(
1337  ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME,
1338  row,
1339  iconTable.tableView_->findCol(DesktopIconTable::COL_APP_LINK));
1340  iconTable.tableView_->setValueAsString(
1341  windowLinkedApp,
1342  row,
1343  iconTable.tableView_->findCol(DesktopIconTable::COL_APP_LINK_UID));
1344  } // end create app link
1345 
1346  // parse parameters
1347  std::map<std::string, std::string> parameters;
1348 
1349  __COUTV__(windowParameters);
1350  StringMacros::getMapFromString(windowParameters, parameters);
1351 
1352  // create link to icon parameters
1353  if(parameters.size())
1354  {
1355  // set parameter link table
1356  iconTable.tableView_->setValueAsString(
1357  DesktopIconTable::PARAMETER_TABLE,
1358  row,
1359  iconTable.tableView_->findCol(DesktopIconTable::COL_PARAMETER_LINK));
1360  // set parameter link Group ID
1361  iconTable.tableView_->setValueAsString(
1362  iconUID + "_Parameters",
1363  row,
1364  iconTable.tableView_->findCol(DesktopIconTable::COL_PARAMETER_LINK_GID));
1365 
1366  __COUTV__(StringMacros::mapToString(parameters));
1367 
1368  unsigned int gidCol =
1369  parameterTable.tableView_->findCol(DesktopIconTable::COL_PARAMETER_GID);
1370 
1371  // remove all existing records from groupID (e.g. parameters leftover from manual manipulations)
1372  std::vector<unsigned int /*row*/> rowsInGroup =
1373  parameterTable.tableView_->getGroupRows(
1374  gidCol, iconUID + "_Parameters" /*groupID*/);
1375 
1376  __COUTV__(StringMacros::vectorToString(rowsInGroup));
1377 
1378  // go through vector backwards to maintain row integrity
1379  for(unsigned int r = rowsInGroup.size() - 1; r < rowsInGroup.size(); --r)
1380  parameterTable.tableView_->removeRowFromGroup(
1381  rowsInGroup[r],
1382  gidCol,
1383  iconUID + "_Parameters" /*groupID*/,
1384  true /*deleteRowIfNoGroupLeft*/);
1385 
1386  // create new parameters
1387  for(const auto& parameter : parameters)
1388  {
1389  // create parameter record
1390  row = parameterTable.tableView_->addRow(
1391  author, true /*incrementUniqueData*/, "generatedParameter");
1392 
1393  // set parameter status true
1394  parameterTable.tableView_->setValueAsString(
1395  "1", row, parameterTable.tableView_->getColStatus());
1396  // set parameter Group ID
1397  parameterTable.tableView_->setValueAsString(
1398  iconUID + "_Parameters", row, gidCol);
1399  // set parameter key
1400  parameterTable.tableView_->setURIEncodedValue(
1401  parameter.first,
1402  row,
1403  parameterTable.tableView_->findCol(
1404  DesktopIconTable::COL_PARAMETER_KEY));
1405  // set parameter value
1406  parameterTable.tableView_->setURIEncodedValue(
1407  parameter.second,
1408  row,
1409  parameterTable.tableView_->findCol(
1410  DesktopIconTable::COL_PARAMETER_VALUE));
1411  } // end parameter loop
1412 
1413  std::stringstream ss;
1414  parameterTable.tableView_->print(ss);
1415  __COUT__ << ss.str();
1416 
1417  parameterTable.tableView_
1418  ->init(); // verify new table (throws runtime_errors)
1419 
1420  } // end create parameters link
1421 
1422  std::stringstream ss;
1423  iconTable.tableView_->print(ss);
1424  __COUT__ << ss.str();
1425 
1426  iconTable.tableView_->init(); // verify new table (throws runtime_errors)
1427  }
1428  catch(...)
1429  {
1430  __COUT__ << "Icon table errors while saving. Erasing all newly "
1431  "created table versions."
1432  << __E__;
1433 
1434  throw; // re-throw
1435  } // end catch
1436 
1437  __COUT__ << "Edits complete for new desktop icon, now making persistent tables."
1438  << __E__;
1439 
1440  // all edits are complete and tables verified
1441 
1442  // Remaining steps:
1443  // save tables
1444  // save new context group and activate it
1445  // check for aliases ...
1446  // if tables aliased.. update table aliases in backbone
1447  // if context group aliased, update group aliases in backbone
1448  // if backbone modified, save group and activate it
1449 
1450  TableGroupKey newContextKey;
1451  bool foundEquivalentContextKey;
1452  TableGroupKey newBackboneKey;
1453  bool foundEquivalentBackboneKey;
1454 
1455  contextGroupEdit.saveChanges(contextGroupEdit.originalGroupName_,
1456  newContextKey,
1457  &foundEquivalentContextKey,
1458  true /*activateNewGroup*/,
1459  true /*updateGroupAliases*/,
1460  true /*updateTableAliases*/,
1461  &newBackboneKey,
1462  &foundEquivalentBackboneKey);
1463 
1464  xmlOut.addTextElementToData("contextGroupName", contextGroupEdit.originalGroupName_);
1465  xmlOut.addTextElementToData("contextGroupKey", newContextKey.toString());
1466 
1467  xmlOut.addTextElementToData("backboneGroupName", backboneGroupName);
1468  xmlOut.addTextElementToData("backboneGroupKey", newBackboneKey.toString());
1469 
1470  // always add active table groups to xml response
1472 
1473  return true;
1474 } // end handleAddDesktopIconXML()
1475 catch(std::runtime_error& e)
1476 {
1477  __SS__ << "Error adding Desktop Icon!\n\n " << e.what() << __E__;
1478  __COUT__ << "\n" << ss.str() << __E__;
1479  xmlOut.addTextElementToData("Error", ss.str());
1480  return false;
1481 }
1482 catch(...)
1483 {
1484  __SS__ << "Error adding Desktop Icon!" << __E__;
1485  try
1486  {
1487  throw;
1488  } //one more try to printout extra info
1489  catch(const std::exception& e)
1490  {
1491  ss << "Exception message: " << e.what();
1492  }
1493  catch(...)
1494  {
1495  }
1496  __COUT__ << "\n" << ss.str() << __E__;
1497  xmlOut.addTextElementToData("Error", ss.str());
1498  return false;
1499 } // end handleAddDesktopIconXML() catch
1500 
1501 //==============================================================================
1502 void ConfigurationSupervisorBase::recursiveCopyTreeUIDNode(
1503  HttpXmlDocument& xmlOut,
1504  ConfigurationManagerRW* cfgMgr,
1505  std::map<std::string /*modified table*/, TableVersion /* modified version */>&
1506  modifiedTablesMap,
1507  const unsigned int startingDepth,
1508  const unsigned int depth,
1509  const unsigned int numberOfInstances,
1510  TableView* cfgView,
1511  const std::string& uidToCopy)
1512 try
1513 {
1514  __COUTV__(startingDepth);
1515  __COUTV__(depth);
1516  __COUTV__(numberOfInstances);
1517 
1518  // throw std::runtime_error("hello");
1519 
1520  // Steps:
1521  // Assume temporary table version already created correctly for recursive level
1522  // Assume already decided it is correct to copy record at row parameter
1523  // Assume after modifications the version saving is handled above this function call
1524  // 1. copy the target row
1525  // - if depth,
1526  // 2. - check source row, for secondary copies through links
1527  // - if a link is found, check that there is not unanimous pointing by siblings
1528  // -- if unanimous pointing by siblings, do not do secondary copy, just point
1529  // 3. -- if not unanimous,
1530  // * use/create temporary version of child table
1531  // * for each instance
1532  // - recursive secondary copy (depth-1)
1533  // * save child table
1534  //
1535 
1536  // Step 1. copy the target row
1537  unsigned int col = cfgView->getColUID();
1538  unsigned int row = cfgView->findRow(col, uidToCopy);
1539 
1540  __COUT__ << "Copying " << cfgView->getTableName() << " v" << cfgView->getVersion()
1541  << " row=" << row << " record=" << uidToCopy
1542  << " instances=" << numberOfInstances << __E__;
1543 
1544  cfgView->print();
1545  // for(unsigned int i = 0; i < numberOfInstances; ++i)
1546  cfgView->copyRows(cfgMgr->getUsername(),
1547  *cfgView /*source table*/,
1548  row,
1549  1 /*srcRowsToCopy*/,
1550  -1 /*destOffsetRow*/,
1551  true /*generateUniqueDataColumns*/,
1552  uidToCopy /*baseNameAutoUID*/); // make the name similar
1553 
1554  // if no secondary copies, done now
1555  // check for secondary copies
1556  return;
1557 
1558  // secondary table copies
1559  std::string tableName = "secondary";
1560  TableVersion version(modifiedTablesMap.at(tableName));
1561 
1562  TableBase* table = cfgMgr->getTableByName(tableName);
1563  try
1564  {
1565  table->setActiveView(version);
1566  }
1567  catch(...)
1568  {
1569  if(version.isTemporaryVersion())
1570  throw; // if temporary, there is no hope to find lost version
1571 
1572  __COUT__ << "Failed to find stored version, so attempting to "
1573  "load version: "
1574  << tableName << " v" << version << __E__;
1575  cfgMgr->getVersionedTableByName(tableName, version);
1576  }
1577 
1578  __COUT__ << tableName << " active version is " << table->getViewVersion() << __E__;
1579 
1580  if(version != table->getViewVersion())
1581  {
1582  __SS__ << "Target table version (" << version
1583  << ") is not the currently active version (" << table->getViewVersion()
1584  << "). Try refreshing the tree." << __E__;
1585  __SS_THROW__;
1586  }
1587 
1588  // version handling:
1589  // always make a new temporary-version from source-version
1590  // edit temporary-version
1591  // if edit fails
1592  // delete temporary-version
1593  // else
1594  // return new temporary-version
1595  // if source-version was temporary
1596  // then delete source-version
1597  TableVersion temporaryVersion = table->createTemporaryView(version);
1598 
1599  __COUT__ << "Created temporary version " << temporaryVersion << __E__;
1600 
1601  cfgView = table->getTemporaryView(temporaryVersion);
1602  cfgView->init(); // prepare maps
1603 
1604  try // while editing
1605  {
1606  // edit...
1607 
1608  cfgView->init(); // verify new table (throws runtime_errors)
1609  }
1610  catch(...) // erase temporary view before re-throwing error
1611  {
1612  __COUT__ << "Caught error while editing. Erasing temporary version." << __E__;
1613  table->eraseView(temporaryVersion);
1614  throw;
1615  }
1616 
1618  xmlOut,
1619  cfgMgr,
1620  tableName,
1621  version,
1622  true /*make temporary*/,
1623  table,
1624  temporaryVersion,
1625  true /*ignoreDuplicates*/); // save temporary version properly
1626 }
1627 catch(std::runtime_error& e)
1628 {
1629  __SS__ << ("Error copying tree target '" + uidToCopy + "' at depth " +
1630  std::to_string(startingDepth - depth) + " in table '" +
1631  cfgView->getTableName() + ".' " + std::string(e.what()))
1632  << __E__;
1633  __COUT__ << "\n" << ss.str() << __E__;
1634  xmlOut.addTextElementToData("Error", ss.str());
1635 }
1636 catch(...)
1637 {
1638  __SS__ << ("Error copying tree target '" + uidToCopy + "' at depth " +
1639  std::to_string(startingDepth - depth) + " in table '" +
1640  cfgView->getTableName() + ".' ")
1641  << __E__;
1642  try
1643  {
1644  throw;
1645  } //one more try to printout extra info
1646  catch(const std::exception& e)
1647  {
1648  ss << "Exception message: " << e.what();
1649  }
1650  catch(...)
1651  {
1652  }
1653  __COUT__ << "\n" << ss.str() << __E__;
1654  xmlOut.addTextElementToData("Error", ss.str());
1655 } // end recursiveCopyTreeUIDNode
TableGroupKey findTableGroup(const std::string &groupName, const std::map< std::string, TableVersion > &groupMembers, const std::map< std::string, std::string > &groupAliases=std::map< std::string, std::string >())
const GroupInfo & getGroupInfo(const std::string &groupName, bool attemptToReloadKeys=false)
public group cache handling
const std::map< std::string, TableInfo > & getAllTableInfo(bool refresh=false, std::string *accumulatedWarnings=0, const std::string &errorFilterName="", bool getGroupKeys=false, bool getGroupInfo=false, bool initializeActiveGroups=false)
void loadTableGroup(const std::string &tableGroupName, const TableGroupKey &tableGroupKey, bool doActivate=false, std::map< std::string, TableVersion > *groupMembers=0, ProgressBar *progressBar=0, std::string *accumulateWarnings=0, std::string *groupComment=0, std::string *groupAuthor=0, std::string *groupCreateTime=0, bool doNotLoadMember=false, std::string *groupTypeString=0, std::map< std::string, std::string > *groupAliases=0, ConfigurationManager::LoadGroupType groupTypeToLoad=ConfigurationManager::LoadGroupType::ALL_TYPES, bool ignoreVersionTracking=false)
TableGroupKey saveNewTableGroup(const std::string &groupName, std::map< std::string, TableVersion > &groupMembers, const std::string &groupComment=TableViewColumnInfo::DATATYPE_COMMENT_DEFAULT, std::map< std::string, std::string > *groupAliases=0)
modifiers of a table group based on alias, e.g. "Physics"
TableVersion saveModifiedVersion(const std::string &tableName, TableVersion originalVersion, bool makeTemporary, TableBase *config, TableVersion temporaryModifiedVersion, bool ignoreDuplicates=false, bool lookForEquivalent=false, bool *foundEquivalent=nullptr)
const std::string & getUsername(void) const
Getters.
std::map< std::string, std::map< std::string, TableVersion > > getVersionAliases(void) const
void restoreActiveTableGroups(bool throwErrors=false, const std::string &pathToActiveGroupsFile="", ConfigurationManager::LoadGroupType onlyLoadIfBackboneOrContext=ConfigurationManager::LoadGroupType::ALL_TYPES, std::string *accumulatedWarnings=0)
std::map< std::string, std::pair< std::string, TableGroupKey > > getActiveTableGroups(void) const
void loadMemberMap(const std::map< std::string, TableVersion > &memberMap, std::string *accumulateWarnings=0)
std::map< std::string, TableVersion > getActiveVersions(void) const
getActiveVersions
ConfigurationTree getNode(const std::string &nodeString, bool doNotThrowOnBrokenUIDLinks=false) const
"root/parent/parent/"
void init(std::string *accumulatedErrors=0, bool initForWriteAccess=false, std::string *accumulatedWarnings=0)
std::vector< std::pair< std::string, ConfigurationTree > > getChildren(std::map< std::string, TableVersion > *memberMap=0, std::string *accumulatedTreeErrors=0) const
static void getConfigurationStatusXML(HttpXmlDocument &xmlOut, ConfigurationManagerRW *cfgMgr, const std::string &username)
getConfigurationStatusXML
static void handleGetTableGroupXML(HttpXmlDocument &xmlOut, ConfigurationManagerRW *cfgMgr, const std::string &groupName, TableGroupKey groupKey, bool ignoreWarnings=false, bool cacheOnly=false)
static TableVersion saveModifiedVersionXML(HttpXmlDocument &xmlOut, ConfigurationManagerRW *cfgMgr, const std::string &tableName, TableVersion originalVersion, bool makeTemporary, TableBase *config, TableVersion temporaryModifiedVersion, bool ignoreDuplicates=false, bool lookForEquivalent=false)
static void handleCreateTableXML(HttpXmlDocument &xmlOut, ConfigurationManagerRW *cfgMgr, const std::string &tableName, TableVersion version, bool makeTemporary, const std::string &data, const int &dataOffset, const std::string &author, const std::string &comment, bool sourceTableAsIs, bool lookForEquivalent)
static void handleCreateTableGroupXML(HttpXmlDocument &xmlOut, ConfigurationManagerRW *cfgMgr, const std::string &groupName, const std::string &configList, bool allowDuplicates=false, bool ignoreWarnings=false, const std::string &groupComment="", bool lookForEquivalent=false)
std::vector< std::pair< std::string, ConfigurationTree > > getChildren(std::map< std::string, std::string > filterMap=std::map< std::string, std::string >(), bool byPriority=false, bool onlyStatusTrue=false) const
TableVersion createTemporaryView(TableVersion sourceViewVersion=TableVersion(), TableVersion destTemporaryViewVersion=TableVersion::getNextTemporaryVersion())
source of -1, from MockUp, else from valid view version
Definition: TableBase.cc:1769
TableView * getTemporaryView(TableVersion temporaryVersion)
Definition: TableBase.cc:1880
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:1081
unsigned int getColStatus(void) const
Definition: TableView.cc:1398
bool removeRowFromGroup(const unsigned int &row, const unsigned int &col, const std::string &groupID, bool deleteRowIfNoGroupLeft=false)
Definition: TableView.cc:1598
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:1488
unsigned int getDataColumnSize(void) const
getDataColumnSize
Definition: TableView.cc:2002
unsigned int getColUID(void) const
Definition: TableView.cc:1313
bool setURIEncodedValue(const std::string &value, const unsigned int &row, const unsigned int &col, const std::string &author="")
Definition: TableView.cc:3387
int fillFromEncodedCSV(const std::string &data, const int &dataOffset=0, const std::string &author="")
Definition: TableView.cc:3251
unsigned int findCol(const std::string &name) const
Definition: TableView.cc:1962
void setURIEncodedComment(const std::string &uriComment)
Definition: TableView.cc:2117
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:3479
xercesc::DOMElement * addTextElementToParent(const std::string &childName, const std::string &childText, xercesc::DOMElement *parent)
Definition: XmlDocument.cc:244
defines used also by OtsConfigurationWizardSupervisor
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)