00001 #include "otsdaq-core/ConfigurationInterface/ConfigurationTree.h"
00002 #include "otsdaq-core/ConfigurationDataFormats/ConfigurationBase.h"
00003
00004 #include "otsdaq-core/ConfigurationInterface/ConfigurationManager.h"
00005
00006 #include <typeinfo>
00007
00008
00009 using namespace ots;
00010
00011
00012 #undef __MF_SUBJECT__
00013 #define __MF_SUBJECT__ "ConfigurationTree"
00014
00015 const std::string ConfigurationTree::DISCONNECTED_VALUE = "X";
00016 const std::string ConfigurationTree::VALUE_TYPE_DISCONNECTED = "Disconnected";
00017 const std::string ConfigurationTree::VALUE_TYPE_NODE = "Node";
00018
00019
00020 ConfigurationTree::ConfigurationTree()
00021 : configMgr_ (0),
00022 configuration_ (0),
00023 groupId_ (""),
00024 linkParentConfig_ (0),
00025 linkColName_ (""),
00026 linkColValue_ (""),
00027 linkBackRow_ (0),
00028 linkBackCol_ (0),
00029 disconnectedTargetName_ (""),
00030 disconnectedLinkID_ (""),
00031 childLinkIndex_ (""),
00032 row_ (0),
00033 col_ (0),
00034 configView_ (0)
00035 {
00036
00037
00038 }
00039
00040 ConfigurationTree::ConfigurationTree(const ConfigurationManager* const &configMgr,
00041 const ConfigurationBase* const &config)
00042 : ConfigurationTree(configMgr, config, "" , 0 ,
00043 "" , "" ,
00044 ConfigurationView::INVALID , ConfigurationView::INVALID ,
00045 "" ,
00046 "" , "" ,
00047 ConfigurationView::INVALID , ConfigurationView::INVALID )
00048 {
00049
00050
00051 }
00052
00053
00054 ConfigurationTree::ConfigurationTree(
00055 const ConfigurationManager* const& configMgr,
00056 const ConfigurationBase* const& config,
00057 const std::string& groupId,
00058 const ConfigurationBase* const& linkParentConfig,
00059 const std::string& linkColName,
00060 const std::string& linkColValue,
00061 const unsigned int linkBackRow,
00062 const unsigned int linkBackCol,
00063 const std::string& disconnectedTargetName,
00064 const std::string& disconnectedLinkID,
00065 const std::string& childLinkIndex,
00066 const unsigned int row,
00067 const unsigned int col)
00068 : configMgr_ (configMgr),
00069 configuration_ (config),
00070 groupId_ (groupId),
00071 linkParentConfig_ (linkParentConfig),
00072 linkColName_ (linkColName),
00073 linkColValue_ (linkColValue),
00074 linkBackRow_ (linkBackRow),
00075 linkBackCol_ (linkBackCol),
00076 disconnectedTargetName_ (disconnectedTargetName),
00077 disconnectedLinkID_ (disconnectedLinkID),
00078 childLinkIndex_ (childLinkIndex),
00079 row_ (row),
00080 col_ (col),
00081 configView_ (0)
00082 {
00083
00084
00085 if(!configMgr_)
00086 {
00087 std::stringstream ss;
00088 ss << __COUT_HDR_FL__ << "Invalid empty pointer given to tree!\n" <<
00089 "\n\tconfigMgr_=" << configMgr_ <<
00090 "\n\tconfiguration_=" << configuration_ <<
00091 "\n\tconfigView_=" << configView_ <<
00092 std::endl;
00093 __COUT__ << "\n" << ss.str();
00094 throw std::runtime_error(ss.str());
00095 }
00096
00097 if(configuration_)
00098 configView_ = &(configuration_->getView());
00099
00100
00101 if(configView_ &&
00102 configView_->getColumnInfo(configView_->getColUID()).getType() != ViewColumnInfo::TYPE_UID)
00103 {
00104 __SS__ << "Missing UID column (must column of type " << ViewColumnInfo::TYPE_UID <<
00105 ") in config view : " << configView_->getTableName() << std::endl;
00106 __COUT__ << "\n" << ss.str();
00107 throw std::runtime_error(ss.str());
00108 }
00109 }
00110
00111
00112
00113 ConfigurationTree::~ConfigurationTree(void)
00114 {
00115
00116 }
00117
00118
00119
00120
00121
00122
00123
00124 void ConfigurationTree::print(const unsigned int &depth, std::ostream &out) const
00125 {
00126 recursivePrint(*this,depth,out,"\t");
00127 }
00128
00129
00130 void ConfigurationTree::recursivePrint(const ConfigurationTree &t, unsigned int depth, std::ostream &out, std::string space)
00131 {
00132 if(t.isValueNode())
00133 out << space << t.getValueName() << " :\t" << t.getValueAsString() << std::endl;
00134 else
00135 {
00136 if(t.isLinkNode())
00137 {
00138 out << space << t.getValueName();
00139 if(t.isDisconnected())
00140 {
00141 out << " :\t" << t.getValueAsString() << std::endl;
00142 return;
00143 }
00144 out << " (" <<
00145 (t.isGroupLinkNode()?"Group":"U") <<
00146 "ID=" << t.getValueAsString() <<
00147 ") : " << std::endl;
00148 }
00149 else
00150 out << space << t.getValueAsString() << " : " << std::endl;
00151
00152
00153
00154 if(depth >= 1)
00155 {
00156 auto C = t.getChildren();
00157 if(!C.empty())
00158 out << space << "{" << std::endl;
00159 for(auto &c:C)
00160 recursivePrint(c.second,depth-1,out,space + " ");
00161 if(!C.empty())
00162 out << space << "}" << std::endl;
00163 }
00164 }
00165 }
00166
00167
00168
00169
00170
00171
00172 void ConfigurationTree::getValue(std::string& value) const
00173 {
00174
00175
00176 if(row_ != ConfigurationView::INVALID && col_ != ConfigurationView::INVALID)
00177 {
00178
00179 try
00180 {
00181 ConfigurationTree valueAsTreeNode = getValueAsTreeNode();
00182
00183 __COUT__ << "Success following path to tree node!" << std::endl;
00184
00185
00186
00187
00188
00189
00190 value = configView_->validateValueForColumn(
00191 valueAsTreeNode.getValueAsString(),col_);
00192
00193
00194 __COUT__ << "Successful value!" << std::endl;
00195
00196
00197
00198
00199
00200 return;
00201 }
00202 catch(...)
00203 {
00204
00205 }
00206
00207
00208 configView_->getValue(value,row_,col_);
00209 }
00210 else if(row_ == ConfigurationView::INVALID && col_ == ConfigurationView::INVALID)
00211 {
00212 if(isLinkNode() && isDisconnected())
00213 value = (groupId_ == "") ? getValueName():groupId_;
00214 else
00215 value = (groupId_ == "") ? configuration_->getConfigurationName():groupId_;
00216 }
00217 else if(row_ == ConfigurationView::INVALID)
00218 {
00219 __SS__ << "Malformed ConfigurationTree" << std::endl;
00220 __COUT_ERR__ << ss.str();
00221 throw std::runtime_error(ss.str());
00222 }
00223 else if(col_ == ConfigurationView::INVALID)
00224 configView_->getValue(value,row_,configView_->getColUID());
00225 else
00226 {
00227 __SS__ << "Impossible." << std::endl;
00228 __COUT_ERR__ << ss.str();
00229 throw std::runtime_error(ss.str());
00230 }
00231
00232 }
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00245
00246 std::string ConfigurationTree::getValue() const
00247 {
00248 std::string value;
00249 ConfigurationTree::getValue(value);
00250 return value;
00251 }
00252
00253
00254
00255
00256 std::string ConfigurationTree::getEscapedValue() const
00257 {
00258 if(row_ != ConfigurationView::INVALID && col_ != ConfigurationView::INVALID)
00259 return configView_->getEscapedValueAsString(row_,col_);
00260
00261 __SS__ << "Can't get escaped value except from a value node!" <<
00262 " This node is type '" << getNodeType() << "." << std::endl;
00263 __COUT_ERR__ << "\n" << ss.str();
00264 throw std::runtime_error(ss.str());
00265 }
00266
00267
00268
00269 const std::string& ConfigurationTree::getConfigurationName(void) const
00270 {
00271 if(!configuration_)
00272 {
00273 __SS__ << "Can't get configuration name of node with no configuration pointer!" << std::endl;
00274 throw std::runtime_error(ss.str());
00275 }
00276 return configuration_->getConfigurationName();
00277 }
00278
00279
00280
00281
00282
00283 const std::string& ConfigurationTree::getFieldConfigurationName(void) const
00284 {
00285
00286 if(isLinkNode())
00287 {
00288 if(!linkParentConfig_)
00289 {
00290 __SS__ << "Can't get configuration name of link node field with no parent configuration pointer!" << std::endl;
00291 throw std::runtime_error(ss.str());
00292 }
00293 return linkParentConfig_->getConfigurationName();
00294 }
00295 else
00296 return getConfigurationName();
00297 }
00298
00299
00300
00301 const std::string& ConfigurationTree::getDisconnectedTableName(void) const
00302 {
00303 if(isLinkNode() && isDisconnected()) return disconnectedTargetName_;
00304
00305 __SS__ << "Can't get disconnected target name of node unless it is a disconnected link node!" << std::endl;
00306 throw std::runtime_error(ss.str());
00307 }
00308
00309
00310
00311 const std::string& ConfigurationTree::getDisconnectedLinkID(void) const
00312 {
00313 if(isLinkNode() && isDisconnected()) return disconnectedLinkID_;
00314
00315 __SS__ << "Can't get disconnected target name of node unless it is a disconnected link node!" << std::endl;
00316 throw std::runtime_error(ss.str());
00317 }
00318
00319
00320
00321 const ConfigurationVersion& ConfigurationTree::getConfigurationVersion(void) const
00322 {
00323 if(!configView_)
00324 {
00325 __SS__ << "Can't get configuration version of node with no config view pointer!" << std::endl;
00326 throw std::runtime_error(ss.str());
00327 }
00328 return configView_->getVersion();
00329 }
00330
00331
00332
00333 const time_t& ConfigurationTree::getConfigurationCreationTime(void) const
00334 {
00335 if(!configView_)
00336 {
00337 __SS__ << "Can't get configuration creation time of node with no config view pointer!" << std::endl;
00338 throw std::runtime_error(ss.str());
00339 }
00340 return configView_->getCreationTime();
00341 }
00342
00343
00344
00345
00346
00347
00348 std::vector<std::string> ConfigurationTree::getFixedChoices(void) const
00349 {
00350 if(!configView_)
00351 {
00352 __SS__ << "Can't get fixed choices of node with no config view pointer!" << std::endl;
00353 throw std::runtime_error(ss.str());
00354 }
00355
00356 if(getValueType() != ViewColumnInfo::TYPE_FIXED_CHOICE_DATA &&
00357 getValueType() != ViewColumnInfo::TYPE_BITMAP_DATA &&
00358 !isLinkNode())
00359 {
00360 __SS__ << "Can't get fixed choices of node with value type of '" <<
00361 getValueType() << ".' Node must be a link or a value node with type '" <<
00362 ViewColumnInfo::TYPE_BITMAP_DATA << "' or '" <<
00363 ViewColumnInfo::TYPE_FIXED_CHOICE_DATA << ".'" << std::endl;
00364 throw std::runtime_error(ss.str());
00365 }
00366
00367 std::vector<std::string> retVec;
00368
00369 if(isLinkNode())
00370 {
00371 if(!linkParentConfig_)
00372 {
00373 __SS__ << "Can't get fixed choices of node with no parent config view pointer!" << std::endl;
00374 throw std::runtime_error(ss.str());
00375 }
00376
00377
00378
00379
00380
00381
00382
00383 const ConfigurationView* parentView = &(linkParentConfig_->getView());
00384 int c = parentView->findCol(linkColName_);
00385
00386 std::pair<unsigned int , unsigned int > linkPair;
00387 bool isGroupLink;
00388 parentView->getChildLink(c, isGroupLink, linkPair);
00389 c = linkPair.first;
00390
00391 std::vector<std::string> choices = parentView->getColumnInfo(c).getDataChoices();
00392 for(const auto &choice:choices)
00393 retVec.push_back(choice);
00394
00395 return retVec;
00396 }
00397
00398
00399 retVec.push_back(configView_->getColumnInfo(col_).getDefaultValue());
00400 std::vector<std::string> choices = configView_->getColumnInfo(col_).getDataChoices();
00401 for(const auto &choice:choices)
00402 retVec.push_back(choice);
00403
00404 return retVec;
00405 }
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415 const std::string& ConfigurationTree::getValueAsString(bool returnLinkTableValue) const
00416 {
00417 if(isLinkNode())
00418 {
00419 if(returnLinkTableValue)
00420 return linkColValue_;
00421 else if(isDisconnected())
00422 return ConfigurationTree::DISCONNECTED_VALUE;
00423 else if(row_ == ConfigurationView::INVALID && col_ == ConfigurationView::INVALID)
00424 return (groupId_ == "")?configuration_->getConfigurationName():groupId_;
00425 else if(col_ == ConfigurationView::INVALID)
00426 return configView_->getDataView()[row_][configView_->getColUID()];
00427 else
00428 {
00429 __SS__ << "Impossible Link." << std::endl;
00430 __COUT_ERR__ << ss.str();
00431 throw std::runtime_error(ss.str());
00432 }
00433 }
00434 else if(row_ != ConfigurationView::INVALID && col_ != ConfigurationView::INVALID)
00435 return configView_->getDataView()[row_][col_];
00436 else if(row_ == ConfigurationView::INVALID && col_ == ConfigurationView::INVALID)
00437 return (groupId_ == "")?configuration_->getConfigurationName():groupId_;
00438 else if(row_ == ConfigurationView::INVALID)
00439 {
00440 __SS__ << "Malformed ConfigurationTree" << std::endl;
00441 __COUT_ERR__ << ss.str();
00442 throw std::runtime_error(ss.str());
00443 }
00444 else if(col_ == ConfigurationView::INVALID)
00445 return configView_->getDataView()[row_][configView_->getColUID()];
00446 else
00447 {
00448 __SS__ << "Impossible." << std::endl;
00449 __COUT_ERR__ << ss.str();
00450 throw std::runtime_error(ss.str());
00451 }
00452 }
00453
00454
00455
00456
00457
00458 const std::string& ConfigurationTree::getUIDAsString(void) const
00459 {
00460 if(isValueNode() || isUIDLinkNode())
00461 return configView_->getDataView()[row_][configView_->getColUID()];
00462
00463 {
00464 __SS__ << "Can't get UID of node with type '" <<
00465 getNodeType() << ".' Node type must be '" <<
00466 ConfigurationTree::NODE_TYPE_VALUE << "' or '" <<
00467 ConfigurationTree::NODE_TYPE_UID_LINK << ".'" << std::endl;
00468 throw std::runtime_error(ss.str());
00469 }
00470 }
00471
00472
00473
00474
00475 const std::string& ConfigurationTree::getValueDataType(void) const
00476 {
00477 if(isValueNode())
00478 return configView_->getColumnInfo(col_).getDataType();
00479 else
00480 return ViewColumnInfo::DATATYPE_STRING;
00481 }
00482
00483
00484
00485
00486 bool ConfigurationTree::isDefaultValue(void) const
00487 {
00488 if(!isValueNode()) return false;
00489
00490 if(getValueDataType() == ViewColumnInfo::DATATYPE_STRING)
00491 {
00492 if(getValueType() == ViewColumnInfo::TYPE_ON_OFF ||
00493 getValueType() == ViewColumnInfo::TYPE_TRUE_FALSE ||
00494 getValueType() == ViewColumnInfo::TYPE_YES_NO)
00495 return getValueAsString() == ViewColumnInfo::DATATYPE_BOOL_DEFAULT;
00496 else if(getValueType() == ViewColumnInfo::TYPE_COMMENT)
00497 return getValueAsString() == ViewColumnInfo::DATATYPE_COMMENT_DEFAULT ||
00498 getValueAsString() == "";
00499 else
00500 return getValueAsString() == ViewColumnInfo::DATATYPE_STRING_DEFAULT;
00501 }
00502 else if(getValueDataType() == ViewColumnInfo::DATATYPE_NUMBER)
00503 return getValueAsString() == ViewColumnInfo::DATATYPE_NUMBER_DEFAULT;
00504 else if(getValueDataType() == ViewColumnInfo::DATATYPE_TIME)
00505 return getValueAsString() == ViewColumnInfo::DATATYPE_TIME_DEFAULT;
00506 else
00507 return false;
00508 }
00509
00510
00511
00512
00513 const std::string& ConfigurationTree::getValueType(void) const
00514 {
00515 if(isValueNode())
00516 return configView_->getColumnInfo(col_).getType();
00517 else if(isLinkNode() && isDisconnected())
00518 return ConfigurationTree::VALUE_TYPE_DISCONNECTED;
00519 else
00520 return ConfigurationTree::VALUE_TYPE_NODE;
00521 }
00522
00523
00524
00525
00526 const ViewColumnInfo& ConfigurationTree::getColumnInfo(void) const
00527 {
00528 if(isValueNode())
00529 return configView_->getColumnInfo(col_);
00530 else
00531 {
00532 __SS__ << "Can only get column info from a value node! " <<
00533 "The node type is " << getNodeType() << std::endl;
00534 __COUT__ << "\n" << ss.str() << std::endl;
00535 throw std::runtime_error(ss.str());
00536 }
00537
00538 }
00539
00540
00541
00542 const unsigned int& ConfigurationTree::getRow(void) const
00543 {
00544 return row_;
00545 }
00546
00547
00548
00549 const unsigned int& ConfigurationTree::getColumn(void) const
00550 {
00551 return col_;
00552 }
00553
00554
00555
00556
00557 const unsigned int& ConfigurationTree::getFieldRow(void) const
00558 {
00559 if(isLinkNode())
00560 {
00561
00562 return linkBackRow_;
00563 }
00564 else
00565 return row_;
00566 }
00567
00568
00569
00570
00571 const unsigned int& ConfigurationTree::getFieldColumn(void) const
00572 {
00573 if(isLinkNode())
00574 {
00575
00576 return linkBackCol_;
00577 }
00578 else
00579 return col_;
00580 }
00581
00582
00583
00584 const std::string& ConfigurationTree::getChildLinkIndex(void) const
00585 {
00586 if(!isLinkNode())
00587 {
00588 __SS__ << "Can only get link ID from a link! " <<
00589 "The node type is " << getNodeType() << std::endl;
00590 __COUT__ << "\n" << ss.str() << std::endl;
00591 throw std::runtime_error(ss.str());
00592 }
00593 return childLinkIndex_;
00594 }
00595
00596
00597
00598
00599 const std::string& ConfigurationTree::getValueName(void) const
00600 {
00601 if(isValueNode())
00602 return configView_->getColumnInfo(col_).getName();
00603 else if(isLinkNode())
00604 return linkColName_;
00605 else
00606 {
00607 __SS__ << "Can only get value name of a value node!" << std::endl;
00608 __COUT__ << "\n" << ss.str() << std::endl;
00609 throw std::runtime_error(ss.str());
00610 }
00611
00612 }
00613
00614
00615
00616
00617 ConfigurationTree ConfigurationTree::recurse(const ConfigurationTree& tree,
00618 const std::string& childPath, bool doNotThrowOnBrokenUIDLinks)
00619 {
00620
00621
00622 if(childPath.length() <= 1)
00623 return tree;
00624 return tree.getNode(childPath,doNotThrowOnBrokenUIDLinks);
00625 }
00626
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660 ConfigurationTree ConfigurationTree::getNode(const std::string &nodeString,
00661 bool doNotThrowOnBrokenUIDLinks) const
00662 {
00663
00664
00665
00666
00667 if(nodeString.length() < 1)
00668 {
00669 __SS__ << "Invalid empty node name! Looking for child node from node '" <<
00670 getValue() << "'..." << std::endl;
00671 __COUT_ERR__ << ss.str();
00672 throw std::runtime_error(ss.str());
00673 }
00674
00675 bool startingSlash = nodeString[0] == '/';
00676
00677 std::string nodeName = nodeString.substr(startingSlash?1:0, nodeString.find('/',1)-(startingSlash?1:0));
00678
00679
00680 std::string childPath = nodeString.substr(nodeName.length() + (startingSlash?1:0));
00681
00682
00683
00684
00685 try
00686 {
00687
00688
00689 if(row_ == ConfigurationView::INVALID && col_ == ConfigurationView::INVALID)
00690 {
00691 if(!configView_)
00692 {
00693 __SS__ << "Missing configView pointer! Likely attempting to access a child node through a disconnected link node." << std::endl;
00694 __COUT_ERR__ << "\n" << ss.str();
00695 throw std::runtime_error(ss.str());
00696 }
00697
00698
00699 return recurse(ConfigurationTree(
00700 configMgr_,
00701 configuration_,
00702 "",
00703 0 ,
00704 "",
00705 "",
00706 ConfigurationView::INVALID , ConfigurationView::INVALID ,
00707 "",
00708 "",
00709 "",
00710
00711 (groupId_ == "")?
00712 configView_->findRow(configView_->getColUID(),nodeName)
00713 : configView_->findRowInGroup(configView_->getColUID(),
00714 nodeName,groupId_,childLinkIndex_) ),
00715 childPath, doNotThrowOnBrokenUIDLinks);
00716 }
00717 else if(row_ == ConfigurationView::INVALID)
00718 {
00719 __SS__ << "Malformed ConfigurationTree" << std::endl;
00720 __COUT_ERR__ << "\n" << ss.str();
00721 throw std::runtime_error(ss.str());
00722 }
00723 else if(col_ == ConfigurationView::INVALID)
00724 {
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735 if(!configView_)
00736 {
00737 __SS__ << "Missing configView pointer! Likely attempting to access a child node through a disconnected link node." << std::endl;
00738 __COUT_ERR__ << "\n" << ss.str();
00739 throw std::runtime_error(ss.str());
00740 }
00741
00742 unsigned int c = configView_->findCol(nodeName);
00743 std::pair<unsigned int , unsigned int > linkPair;
00744 bool isGroupLink, isLink;
00745 if((isLink = configView_->getChildLink(c, isGroupLink, linkPair)) &&
00746 !isGroupLink)
00747 {
00748
00749
00750
00751
00752
00753 const ConfigurationBase* childConfig;
00754 try
00755 {
00756 childConfig = configMgr_->getConfigurationByName(configView_->getDataView()[row_][linkPair.first]);
00757 childConfig->getView();
00758
00759 if(doNotThrowOnBrokenUIDLinks)
00760 {
00761 childConfig->getView().findRow(childConfig->getView().getColUID(),
00762 configView_->getDataView()[row_][linkPair.second]);
00763 }
00764 }
00765 catch(...)
00766 {
00767
00768
00769
00770
00771
00772
00773 return ConfigurationTree(
00774 configMgr_,
00775 0,
00776 "",
00777 configuration_,
00778 nodeName,
00779 configView_->getDataView()[row_][c],
00780 row_ , c ,
00781 configView_->getDataView()[row_][linkPair.first],
00782 configView_->getDataView()[row_][linkPair.second],
00783 configView_->getColumnInfo(c).getChildLinkIndex());
00784 }
00785
00786 return recurse(
00787 ConfigurationTree(
00788 configMgr_,
00789 childConfig,
00790 "",
00791 configuration_,
00792 nodeName,
00793 configView_->getDataView()[row_][c],
00794 row_ , c ,
00795 "",
00796 "",
00797 configView_->getColumnInfo(c).getChildLinkIndex(),
00798 childConfig->getView().findRow(childConfig->getView().getColUID(),
00799 configView_->getDataView()[row_][linkPair.second])
00800 ),
00801 childPath, doNotThrowOnBrokenUIDLinks);
00802 }
00803 else if(isLink)
00804 {
00805
00806
00807
00808
00809
00810 const ConfigurationBase* childConfig;
00811 try
00812 {
00813 childConfig = configMgr_->getConfigurationByName(
00814 configView_->getDataView()[row_][linkPair.first]);
00815 childConfig->getView();
00816 }
00817 catch(...)
00818 {
00819 if(configView_->getDataView()[row_][linkPair.first] !=
00820 ViewColumnInfo::DATATYPE_LINK_DEFAULT)
00821 __COUT_WARN__ << "Found disconnected node! Failed link target from nodeName=" <<
00822 nodeName << " to table:id=" <<
00823 configView_->getDataView()[row_][linkPair.first] << ":" <<
00824 configView_->getDataView()[row_][linkPair.second] <<
00825 std::endl;
00826
00827
00828 return ConfigurationTree(configMgr_,0,
00829 configView_->getDataView()[row_][linkPair.second],
00830 configuration_,
00831 nodeName,
00832 configView_->getDataView()[row_][c],
00833 row_ , c ,
00834 configView_->getDataView()[row_][linkPair.first],
00835 configView_->getDataView()[row_][linkPair.second],
00836 configView_->getColumnInfo(c).getChildLinkIndex()
00837 );
00838 }
00839
00840 return recurse(
00841 ConfigurationTree(
00842 configMgr_,
00843 childConfig,
00844 configView_->getDataView()[row_][linkPair.second],
00845 configuration_,
00846 nodeName,
00847 configView_->getDataView()[row_][c],
00848 row_ , c ,
00849 "",
00850 "",
00851 configView_->getColumnInfo(c).getChildLinkIndex()
00852 ),
00853 childPath, doNotThrowOnBrokenUIDLinks);
00854 }
00855 else
00856 {
00857
00858
00859 return ConfigurationTree(
00860 configMgr_,
00861 configuration_,"",
00862 0 ,
00863 "","",
00864 ConfigurationView::INVALID , ConfigurationView::INVALID ,
00865 "","","",
00866 row_,c);
00867 }
00868 }
00869
00870 }
00871 catch(std::runtime_error &e)
00872 {
00873 __SS__ << "\n\nError occurred descending from node '" << getValue() <<
00874 "' in table '" << getConfigurationName() <<
00875 "' looking for child '" << nodeName << "'\n\n" << std::endl;
00876 ss << "--- Additional error detail: \n\n" << e.what() << std::endl;
00877 throw std::runtime_error(ss.str());
00878 }
00879 catch(...)
00880 {
00881 __SS__ << "\n\nError occurred descending from node '" << getValue() <<
00882 "' in table '" << getConfigurationName() <<
00883 "' looking for child '" << nodeName << "'\n\n" << std::endl;
00884 throw std::runtime_error(ss.str());
00885 }
00886
00887
00888 __SS__ << "\n\nError occurred descending from node '" << getValue() <<
00889 "' in table '" << getConfigurationName() <<
00890 "' looking for child '" << nodeName << "'\n\n" <<
00891 "Invalid depth! getNode() called from a value point in the Configuration Tree." << std::endl;
00892 throw std::runtime_error(ss.str());
00893 }
00894
00895
00896
00897 ConfigurationTree ConfigurationTree::getBackNode(std::string nodeName, unsigned int backSteps) const
00898 {
00899 for(unsigned int i=0; i<backSteps; i++)
00900 nodeName = nodeName.substr(0, nodeName.find_last_of('/'));
00901
00902 return getNode(nodeName);
00903 }
00904
00905
00906
00907
00908 bool ConfigurationTree::isValueNode(void) const
00909 {
00910 return (row_ != ConfigurationView::INVALID && col_ != ConfigurationView::INVALID);
00911 }
00912
00913
00914
00915
00916
00917
00918 bool ConfigurationTree::isDisconnected(void) const
00919 {
00920 if(!isLinkNode())
00921 {
00922 __SS__ << "\n\nError occurred testing link connection at node with value '" <<
00923 getValue() <<
00924 "' in table '" << getConfigurationName() <<
00925 "'\n\n" << std::endl;
00926 ss << "This is not a Link node! It is node type '" <<
00927 getNodeType() << ".' Only a Link node can be disconnected." << std::endl;
00928
00929 throw std::runtime_error(ss.str());
00930 }
00931
00932 return !configuration_ || !configView_;
00933 }
00934
00935
00936
00937
00938 bool ConfigurationTree::isLinkNode(void) const
00939 {
00940 return linkColName_ != "";
00941 }
00942
00943
00944
00945
00946 const std::string ConfigurationTree::NODE_TYPE_GROUP_TABLE = "GroupConfigurationNode";
00947 const std::string ConfigurationTree::NODE_TYPE_TABLE = "ConfigurationNode";
00948 const std::string ConfigurationTree::NODE_TYPE_GROUP_LINK = "GroupLinkNode";
00949 const std::string ConfigurationTree::NODE_TYPE_UID_LINK = "UIDLinkNode";
00950 const std::string ConfigurationTree::NODE_TYPE_VALUE = "ValueNode";
00951 const std::string ConfigurationTree::NODE_TYPE_UID = "UIDNode";
00952 std::string ConfigurationTree::getNodeType(void) const
00953 {
00954 if(isConfigurationNode() && groupId_ != "") return ConfigurationTree::NODE_TYPE_GROUP_TABLE;
00955 if(isConfigurationNode()) return ConfigurationTree::NODE_TYPE_TABLE;
00956 if(isGroupLinkNode()) return ConfigurationTree::NODE_TYPE_GROUP_LINK;
00957 if(isLinkNode()) return ConfigurationTree::NODE_TYPE_UID_LINK;
00958 if(isValueNode()) return ConfigurationTree::NODE_TYPE_VALUE;
00959 return ConfigurationTree::NODE_TYPE_UID;
00960 }
00961
00962
00963
00964
00965 bool ConfigurationTree::isGroupLinkNode(void) const
00966 {
00967 return (isLinkNode() && groupId_ != "");
00968 }
00969
00970
00971
00972
00973 bool ConfigurationTree::isUIDLinkNode(void) const
00974 {
00975 return (isLinkNode() && groupId_ == "");
00976 }
00977
00978
00979
00980
00981 bool ConfigurationTree::isUIDNode(void) const
00982 {
00983 return (row_ != ConfigurationView::INVALID && col_ == ConfigurationView::INVALID);
00984 }
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003 std::vector<ConfigurationTree::RecordField> ConfigurationTree::getCommonFields(
01004 const std::vector<std::string /*uid*/> &recordList,
01005 const std::vector<std::string /*relative-path*/> &fieldAcceptList,
01006 const std::vector<std::string /*relative-path*/> &fieldRejectList,
01007 unsigned int depth) const
01008 {
01009
01010 if(!isConfigurationNode())
01011 {
01012 __SS__ << "Can only get getCommonFields from a table node! " <<
01013 "The node type is " << getNodeType() << std::endl;
01014 __COUT__ << "\n" << ss.str() << std::endl;
01015 throw std::runtime_error(ss.str());
01016 }
01017
01018 std::vector<ConfigurationTree::RecordField> fieldCandidateList;
01019 std::vector<int> fieldCount;
01020
01021 --depth;
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056 bool found;
01057 auto tableName = getConfigurationName();
01058
01059 for(unsigned int i=0;i<recordList.size();++i)
01060 {
01061
01062
01063 auto recordChildren = getNode(recordList[i]).getChildren();
01064 for(const auto &fieldNode : recordChildren)
01065 {
01066
01067
01068 if(fieldNode.second.isValueNode())
01069 {
01070
01071 if(fieldNode.second.getColumnInfo().getType() ==
01072 ViewColumnInfo::TYPE_AUTHOR ||
01073 fieldNode.second.getColumnInfo().getType() ==
01074 ViewColumnInfo::TYPE_TIMESTAMP)
01075 continue;
01076
01077
01078 if(!i)
01079 {
01080
01081 found = fieldAcceptList.size()?false:true;
01082 for(const auto &fieldFilter : fieldAcceptList)
01083 if(ConfigurationTree::wildCardMatch(
01084 fieldFilter,fieldNode.first))
01085 {
01086 found = true;
01087 break;
01088 }
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118 if(found)
01119 {
01120
01121
01122 found = true;
01123 for(const auto &fieldFilter : fieldRejectList)
01124 if(ConfigurationTree::wildCardMatch(
01125 fieldFilter,fieldNode.first))
01126 {
01127 found = false;
01128 break;
01129 }
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159 }
01160
01161
01162 if(found)
01163 {
01164 fieldCandidateList.push_back(
01165 ConfigurationTree::RecordField(
01166 tableName,
01167 recordList[i],
01168 fieldNode.first,
01169 "",
01170 &fieldNode.second.getColumnInfo()
01171 ));
01172 fieldCount.push_back(-1);
01173 }
01174 }
01175
01176
01177 }
01178 else if(depth > 0 &&
01179 fieldNode.second.isUIDLinkNode() &&
01180 !fieldNode.second.isDisconnected())
01181 {
01182
01183 fieldNode.second.recursiveGetCommonFields(
01184 fieldCandidateList,
01185 fieldCount,
01186 fieldAcceptList,
01187 fieldRejectList,
01188 depth,
01189 fieldNode.first + "/",
01190 !i
01191 );
01192 }
01193 }
01194
01195 }
01196
01197
01198
01199
01200
01201
01202 for(unsigned int i=0;i<fieldCandidateList.size();++i)
01203 {
01204
01205
01206
01207 if(fieldCount[i] != -1 &&
01208 fieldCount[i] != (int)recordList.size())
01209 {
01210
01211
01212
01213 fieldCount.erase(fieldCount.begin() + i);
01214 fieldCandidateList.erase(fieldCandidateList.begin() + i);
01215 --i;
01216 }
01217 }
01218
01219
01220
01221
01222
01223 return fieldCandidateList;
01224 }
01225
01226
01227
01228
01229
01230
01231 std::set<std::string > ConfigurationTree::getUniqueValuesForField(
01232 const std::vector<std::string /*relative-path*/> &recordList,
01233 const std::string &fieldName) const
01234 {
01235
01236 if(!isConfigurationNode())
01237 {
01238 __SS__ << "Can only get getCommonFields from a table node! " <<
01239 "The node type is " << getNodeType() << std::endl;
01240 __COUT__ << "\n" << ss.str() << std::endl;
01241 throw std::runtime_error(ss.str());
01242 }
01243
01244 std::set<std::string > uniqueValues;
01245
01246
01247
01248
01249
01250
01251 for(unsigned int i=0;i<recordList.size();++i)
01252 {
01253 __COUT__ << "Checking " << recordList[i] << std::endl;
01254
01255
01256
01257
01258
01259
01260
01261 uniqueValues.emplace(getNode(recordList[i]).getNode(fieldName).getValueAsString(true));
01262 }
01263
01264 return uniqueValues;
01265 }
01266
01267
01268
01269
01270 void ConfigurationTree::recursiveGetCommonFields(
01271 std::vector<ConfigurationTree::RecordField> &fieldCandidateList,
01272 std::vector<int> &fieldCount,
01273 const std::vector<std::string /*relative-path*/> &fieldAcceptList,
01274 const std::vector<std::string /*relative-path*/> &fieldRejectList,
01275 unsigned int depth,
01276 const std::string &relativePathBase,
01277 bool inFirstRecord
01278 ) const
01279 {
01280 --depth;
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302 bool found;
01303 auto tableName = getConfigurationName();
01304 auto uid = getUIDAsString();
01305 unsigned int j;
01306
01307 auto recordChildren = getChildren();
01308 for(const auto &fieldNode : recordChildren)
01309 {
01310 if(fieldNode.second.isValueNode())
01311 {
01312
01313 if(fieldNode.second.getColumnInfo().getType() ==
01314 ViewColumnInfo::TYPE_AUTHOR ||
01315 fieldNode.second.getColumnInfo().getType() ==
01316 ViewColumnInfo::TYPE_TIMESTAMP)
01317 continue;
01318
01319
01320 if(inFirstRecord)
01321 {
01322
01323 found = fieldAcceptList.size()?false:true;
01324 for(const auto &fieldFilter : fieldAcceptList)
01325 if(ConfigurationTree::wildCardMatch(
01326 fieldFilter,fieldNode.first))
01327 {
01328 found = true;
01329 break;
01330 }
01331
01332
01333
01334
01335
01336
01337
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349
01350
01351
01352
01353
01354
01355
01356
01357
01358
01359
01360
01361 if(found)
01362 {
01363
01364
01365 found = true;
01366 for(const auto &fieldFilter : fieldRejectList)
01367 if(ConfigurationTree::wildCardMatch(
01368 fieldFilter,fieldNode.first))
01369 {
01370 found = false;
01371 break;
01372 }
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402 }
01403
01404
01405 if(found)
01406 {
01407
01408
01409 fieldCandidateList.push_back(
01410 ConfigurationTree::RecordField(
01411 tableName,
01412 uid,
01413 fieldNode.first,
01414 relativePathBase,
01415 &fieldNode.second.getColumnInfo()
01416 ));
01417 fieldCount.push_back(1);
01418 }
01419 }
01420 else
01421 {
01422
01423
01424 for(j=0;j<fieldCandidateList.size();++j)
01425 {
01426 if((relativePathBase + fieldNode.first) ==
01427 (fieldCandidateList[j].relativePath_ +
01428 fieldCandidateList[j].columnName_))
01429 {
01430
01431
01432
01433 ++fieldCount[j];
01434 break;
01435 }
01436 }
01437 }
01438 }
01439 else if(depth > 0 &&
01440 fieldNode.second.isUIDLinkNode() &&
01441 !fieldNode.second.isDisconnected())
01442 {
01443
01444 fieldNode.second.recursiveGetCommonFields(
01445 fieldCandidateList,
01446 fieldCount,
01447 fieldAcceptList,
01448 fieldRejectList,
01449 depth,
01450 (relativePathBase + fieldNode.first) + "/",
01451 inFirstRecord
01452 );
01453 }
01454 }
01455 }
01456
01457
01458
01459
01460
01461 std::vector<std::pair<std::string,ConfigurationTree> > ConfigurationTree::getChildren(
01462 std::map<std::string /*relative-path*/, std::string /*value*/> filterMap) const
01463 {
01464 std::vector<std::pair<std::string,ConfigurationTree> > retMap;
01465
01466
01467
01468 bool filtering = filterMap.size();
01469 bool skip;
01470 std::string fieldValue;
01471
01472 std::vector<std::string> childrenNames = getChildrenNames();
01473 for(auto &childName : childrenNames)
01474 {
01475
01476
01477 if(filtering)
01478 {
01479
01480 skip = false;
01481
01482
01483 for(const auto &filterPair:filterMap)
01484 {
01485 std::string filterPath = childName + "/" + filterPair.first;
01486 try
01487 {
01488
01489
01490 std::istringstream f(filterPair.second);
01491
01492 skip = true;
01493
01494 while (getline(f, fieldValue, ','))
01495 {
01496
01497
01498
01499
01500
01501
01502
01503 __COUT__ << "\t\tCheck: " << filterPair.first <<
01504 " == " << fieldValue << " ??? " <<
01505 this->getNode(filterPath).getValueAsString(true) <<
01506 std::endl;
01507
01508 if(ConfigurationTree::wildCardMatch(
01509 ConfigurationView::decodeURIComponent(fieldValue),
01510 this->getNode(filterPath).getValueAsString(true) ))
01511 {
01512
01513 skip = false;
01514 break;
01515 }
01516
01517
01518
01519
01520
01521
01522
01523
01524 }
01525 }
01526 catch(...)
01527 {
01528 __SS__ << "Failed to access filter path '" <<
01529 filterPath << "' - aborting." << std::endl;
01530 __COUT_ERR__ << "\n" << ss.str();
01531 throw std::runtime_error(ss.str());
01532 }
01533
01534 if(skip) break;
01535 }
01536
01537 if(skip) continue;
01538
01539 __COUT__ << "\tChild accepted: " << childName << std::endl;
01540 }
01541
01542 retMap.push_back(std::pair<std::string,ConfigurationTree>(childName,
01543 this->getNode(childName, true)));
01544 }
01545
01546
01547 return retMap;
01548 }
01549
01550
01551
01552
01553
01554 bool ConfigurationTree::wildCardMatch(const std::string& needle, const std::string& haystack)
01555 try
01556 {
01557
01558
01559
01560
01561 if(needle.size() == 0)
01562 return true;
01563
01564 if(needle[0] == '*' &&
01565 needle[needle.size()-1] == '*' )
01566 return std::string::npos != haystack.find(needle.substr(1,needle.size()-2));
01567
01568 if(needle[0] == '*')
01569 return needle.substr(1) ==
01570 haystack.substr(haystack.size() - (needle.size()-1));
01571
01572 if(needle[needle.size()-1] == '*')
01573 return needle.substr(0,needle.size()-1) ==
01574 haystack.substr(0,needle.size()-1);
01575
01576
01577 return needle == haystack;
01578 }
01579 catch(...)
01580 {
01581 return false;
01582 }
01583
01584
01585
01586
01587
01588 std::map<std::string,ConfigurationTree> ConfigurationTree::getChildrenMap(void) const
01589 {
01590 std::map<std::string,ConfigurationTree> retMap;
01591
01592
01593
01594 std::vector<std::string> childrenNames = getChildrenNames();
01595 for(auto& childName : childrenNames)
01596 {
01597
01598 retMap.insert(std::pair<std::string,ConfigurationTree>(childName, this->getNode(childName)));
01599 }
01600
01601
01602 return retMap;
01603 }
01604
01605
01606 bool ConfigurationTree::isConfigurationNode(void) const
01607 {
01608 return (row_ == ConfigurationView::INVALID && col_ == ConfigurationView::INVALID);
01609 }
01610
01611
01612
01613
01614 std::vector<std::string> ConfigurationTree::getChildrenNames(void) const
01615 {
01616 std::vector<std::string> retSet;
01617
01618 if(!configView_)
01619 {
01620 __SS__ << "Can not get children names of '" <<
01621 getValueAsString() <<
01622 "' with null configuration view pointer!" << std::endl;
01623 if(isLinkNode() && isDisconnected())
01624 ss << " This node is a disconnected link to " <<
01625 getDisconnectedTableName() << std::endl;
01626 __COUT_ERR__ << "\n" << ss.str();
01627 throw std::runtime_error(ss.str());
01628 }
01629
01630 if(row_ == ConfigurationView::INVALID && col_ == ConfigurationView::INVALID)
01631 {
01632
01633
01634
01635 for(unsigned int r = 0; r<configView_->getNumberOfRows(); ++r)
01636 if(groupId_ == "" ||
01637 configView_->isEntryInGroup(r,childLinkIndex_,groupId_))
01638
01639
01640 retSet.push_back(configView_->getDataView()[r][configView_->getColUID()]);
01641 }
01642 else if(row_ == ConfigurationView::INVALID)
01643 {
01644 __SS__ << "Malformed ConfigurationTree" << std::endl;
01645 __COUT_ERR__ << ss.str();
01646 throw std::runtime_error(ss.str());
01647 }
01648 else if(col_ == ConfigurationView::INVALID)
01649 {
01650
01651
01652
01653 for(unsigned int c = 0; c<configView_->getNumberOfColumns(); ++c)
01654 if(c == configView_->getColUID() ||
01655 configView_->getColumnInfo(c).isChildLinkGroupID() ||
01656 configView_->getColumnInfo(c).isChildLinkUID())
01657 continue;
01658 else
01659 retSet.push_back(configView_->getColumnInfo(c).getName());
01660 }
01661 else
01662 {
01663
01664 __SS__ << "\n\nError occurred looking for children of nodeName=" << getValueName() << "\n\n" <<
01665 "Invalid depth! getChildrenValues() called from a value point in the Configuration Tree." << std::endl;
01666 __COUT_ERR__ << ss.str();
01667 throw std::runtime_error(ss.str());
01668 }
01669
01670 return retSet;
01671 }
01672
01673
01674
01675
01676
01677
01678 ConfigurationTree ConfigurationTree::getValueAsTreeNode(void) const
01679 {
01680
01681
01682
01683 if(!configView_)
01684 {
01685 __SS__ << "Invalid node for get value." << std::endl;
01686 __COUT__ << ss.str();
01687 throw std::runtime_error(ss.str());
01688 }
01689
01690 std::string valueString = configView_->getValueAsString(row_,col_,true );
01691
01692 if(valueString.size() && valueString[0] == '/')
01693 {
01694
01695 try
01696 {
01697 ConfigurationTree retNode = configMgr_->getNode(valueString);
01698 __COUT__ << "Found a valid tree path in value!" << std::endl;
01699 return retNode;
01700 }
01701 catch(...)
01702 {
01703 __SS__ << "Invalid tree path." << std::endl;
01704
01705 throw std::runtime_error(ss.str());
01706 }
01707 }
01708
01709
01710 {
01711 __SS__ << "Invalid value string '" << valueString <<
01712 "' - must start with a '/' character." << std::endl;
01713 throw std::runtime_error(ss.str());
01714 }
01715 }
01716
01717
01718
01719
01720
01721
01722
01723
01724
01725
01726