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