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 not 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 not 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 not 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 not 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 not 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 not 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 not 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(getValueType() != ViewColumnInfo::TYPE_FIXED_CHOICE_DATA &&
00351 getValueType() != ViewColumnInfo::TYPE_BITMAP_DATA &&
00352 !isLinkNode())
00353 {
00354 __SS__ << "Can not get fixed choices of node with value type of '" <<
00355 getValueType() << ".' Node must be a link or a value node with type '" <<
00356 ViewColumnInfo::TYPE_BITMAP_DATA << "' or '" <<
00357 ViewColumnInfo::TYPE_FIXED_CHOICE_DATA << ".'" << std::endl;
00358 throw std::runtime_error(ss.str());
00359 }
00360
00361 std::vector<std::string> retVec;
00362
00363 if(isLinkNode())
00364 {
00365 if(!linkParentConfig_)
00366 {
00367 __SS__ << "Can not get fixed choices of node with no parent config view pointer!" << std::endl;
00368 throw std::runtime_error(ss.str());
00369 }
00370
00371
00372
00373
00374
00375
00376
00377 const ConfigurationView* parentView = &(linkParentConfig_->getView());
00378 int c = parentView->findCol(linkColName_);
00379
00380 std::pair<unsigned int , unsigned int > linkPair;
00381 bool isGroupLink;
00382 parentView->getChildLink(c, isGroupLink, linkPair);
00383 c = linkPair.first;
00384
00385 std::vector<std::string> choices = parentView->getColumnInfo(c).getDataChoices();
00386 for(const auto &choice:choices)
00387 retVec.push_back(choice);
00388
00389 return retVec;
00390 }
00391
00392 if(!configView_)
00393 {
00394 __SS__ << "Can not get fixed choices of node with no config view pointer!" << std::endl;
00395 throw std::runtime_error(ss.str());
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 not 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(!configuration_)
00690 {
00691
00692
00693 return recurse(
00694 configMgr_->getNode(nodeName),
00695 childPath, doNotThrowOnBrokenUIDLinks);
00696 }
00697 else if(row_ == ConfigurationView::INVALID && col_ == ConfigurationView::INVALID)
00698 {
00699
00700
00701 if(!configView_)
00702 {
00703 __SS__ << "Missing configView pointer! Likely attempting to access a child node through a disconnected link node." << std::endl;
00704 __COUT_ERR__ << "\n" << ss.str();
00705 throw std::runtime_error(ss.str());
00706 }
00707
00708
00709 return recurse(ConfigurationTree(
00710 configMgr_,
00711 configuration_,
00712 "",
00713 0 ,
00714 "",
00715 "",
00716 ConfigurationView::INVALID , ConfigurationView::INVALID ,
00717 "",
00718 "",
00719 "",
00720
00721 (groupId_ == "")?
00722 configView_->findRow(configView_->getColUID(),nodeName)
00723 : configView_->findRowInGroup(configView_->getColUID(),
00724 nodeName,groupId_,childLinkIndex_) ),
00725 childPath, doNotThrowOnBrokenUIDLinks);
00726 }
00727 else if(row_ == ConfigurationView::INVALID)
00728 {
00729 __SS__ << "Malformed ConfigurationTree" << std::endl;
00730 __COUT_ERR__ << "\n" << ss.str();
00731 throw std::runtime_error(ss.str());
00732 }
00733 else if(col_ == ConfigurationView::INVALID)
00734 {
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745 if(!configView_)
00746 {
00747 __SS__ << "Missing configView pointer! Likely attempting to access a child node through a disconnected link node." << std::endl;
00748 __COUT_ERR__ << "\n" << ss.str();
00749 throw std::runtime_error(ss.str());
00750 }
00751
00752 unsigned int c = configView_->findCol(nodeName);
00753 std::pair<unsigned int , unsigned int > linkPair;
00754 bool isGroupLink, isLink;
00755 if((isLink = configView_->getChildLink(c, isGroupLink, linkPair)) &&
00756 !isGroupLink)
00757 {
00758
00759
00760
00761
00762
00763 const ConfigurationBase* childConfig;
00764 try
00765 {
00766 childConfig = configMgr_->getConfigurationByName(configView_->getDataView()[row_][linkPair.first]);
00767 childConfig->getView();
00768
00769 if(doNotThrowOnBrokenUIDLinks)
00770 {
00771 childConfig->getView().findRow(childConfig->getView().getColUID(),
00772 configView_->getDataView()[row_][linkPair.second]);
00773 }
00774 }
00775 catch(...)
00776 {
00777
00778
00779
00780
00781
00782
00783 return ConfigurationTree(
00784 configMgr_,
00785 0,
00786 "",
00787 configuration_,
00788 nodeName,
00789 configView_->getDataView()[row_][c],
00790 row_ , c ,
00791 configView_->getDataView()[row_][linkPair.first],
00792 configView_->getDataView()[row_][linkPair.second],
00793 configView_->getColumnInfo(c).getChildLinkIndex());
00794 }
00795
00796 return recurse(
00797 ConfigurationTree(
00798 configMgr_,
00799 childConfig,
00800 "",
00801 configuration_,
00802 nodeName,
00803 configView_->getDataView()[row_][c],
00804 row_ , c ,
00805 "",
00806 "",
00807 configView_->getColumnInfo(c).getChildLinkIndex(),
00808 childConfig->getView().findRow(childConfig->getView().getColUID(),
00809 configView_->getDataView()[row_][linkPair.second])
00810 ),
00811 childPath, doNotThrowOnBrokenUIDLinks);
00812 }
00813 else if(isLink)
00814 {
00815
00816
00817
00818
00819
00820 const ConfigurationBase* childConfig;
00821 try
00822 {
00823 childConfig = configMgr_->getConfigurationByName(
00824 configView_->getDataView()[row_][linkPair.first]);
00825 childConfig->getView();
00826 }
00827 catch(...)
00828 {
00829 if(configView_->getDataView()[row_][linkPair.first] !=
00830 ViewColumnInfo::DATATYPE_LINK_DEFAULT)
00831 __COUT_WARN__ << "Found disconnected node! Failed link target from nodeName=" <<
00832 nodeName << " to table:id=" <<
00833 configView_->getDataView()[row_][linkPair.first] << ":" <<
00834 configView_->getDataView()[row_][linkPair.second] <<
00835 std::endl;
00836
00837
00838 return ConfigurationTree(configMgr_,0,
00839 configView_->getDataView()[row_][linkPair.second],
00840 configuration_,
00841 nodeName,
00842 configView_->getDataView()[row_][c],
00843 row_ , c ,
00844 configView_->getDataView()[row_][linkPair.first],
00845 configView_->getDataView()[row_][linkPair.second],
00846 configView_->getColumnInfo(c).getChildLinkIndex()
00847 );
00848 }
00849
00850 return recurse(
00851 ConfigurationTree(
00852 configMgr_,
00853 childConfig,
00854 configView_->getDataView()[row_][linkPair.second],
00855 configuration_,
00856 nodeName,
00857 configView_->getDataView()[row_][c],
00858 row_ , c ,
00859 "",
00860 "",
00861 configView_->getColumnInfo(c).getChildLinkIndex()
00862 ),
00863 childPath, doNotThrowOnBrokenUIDLinks);
00864 }
00865 else
00866 {
00867
00868
00869 return ConfigurationTree(
00870 configMgr_,
00871 configuration_,"",
00872 0 ,
00873 "","",
00874 ConfigurationView::INVALID , ConfigurationView::INVALID ,
00875 "","","",
00876 row_,c);
00877 }
00878 }
00879
00880 }
00881 catch(std::runtime_error &e)
00882 {
00883 __SS__ << "\n\nError occurred descending from node '" << getValue() <<
00884 "' in table '" << getConfigurationName() <<
00885 "' looking for child '" << nodeName << "'\n\n" << std::endl;
00886 ss << "--- Additional error detail: \n\n" << e.what() << std::endl;
00887 throw std::runtime_error(ss.str());
00888 }
00889 catch(...)
00890 {
00891 __SS__ << "\n\nError occurred descending from node '" << getValue() <<
00892 "' in table '" << getConfigurationName() <<
00893 "' looking for child '" << nodeName << "'\n\n" << std::endl;
00894 throw std::runtime_error(ss.str());
00895 }
00896
00897
00898 __SS__ << "\n\nError occurred descending from node '" << getValue() <<
00899 "' in table '" << getConfigurationName() <<
00900 "' looking for child '" << nodeName << "'\n\n" <<
00901 "Invalid depth! getNode() called from a value point in the Configuration Tree." << std::endl;
00902 throw std::runtime_error(ss.str());
00903 }
00904
00905
00906
00907 ConfigurationTree ConfigurationTree::getBackNode(std::string nodeName, unsigned int backSteps) const
00908 {
00909 for(unsigned int i=0; i<backSteps; i++)
00910 nodeName = nodeName.substr(0, nodeName.find_last_of('/'));
00911
00912 return getNode(nodeName);
00913 }
00914
00915
00916 ConfigurationTree ConfigurationTree::getForwardNode(std::string nodeName, unsigned int forwardSteps) const
00917 {
00918 unsigned int s = 0;
00919
00920
00921 while(s < nodeName.length() && nodeName[s] == '/') ++s;
00922
00923 for(unsigned int i=0; i<forwardSteps; i++)
00924 s = nodeName.find('/',s) + 1;
00925
00926 return getNode(nodeName.substr(0,s));
00927 }
00928
00929
00930
00931 bool ConfigurationTree::isValueNode(void) const
00932 {
00933 return (row_ != ConfigurationView::INVALID && col_ != ConfigurationView::INVALID);
00934 }
00935
00936
00937
00938
00939
00940
00941 bool ConfigurationTree::isDisconnected(void) const
00942 {
00943 if(!isLinkNode())
00944 {
00945 __SS__ << "\n\nError occurred testing link connection at node with value '" <<
00946 getValue() <<
00947 "' in table '" << getConfigurationName() <<
00948 "'\n\n" << std::endl;
00949 ss << "This is not a Link node! It is node type '" <<
00950 getNodeType() << ".' Only a Link node can be disconnected." << std::endl;
00951
00952 throw std::runtime_error(ss.str());
00953 }
00954
00955 return !configuration_ || !configView_;
00956 }
00957
00958
00959
00960
00961 bool ConfigurationTree::isLinkNode(void) const
00962 {
00963 return linkColName_ != "";
00964 }
00965
00966
00967
00968
00969 const std::string ConfigurationTree::NODE_TYPE_GROUP_TABLE = "GroupConfigurationNode";
00970 const std::string ConfigurationTree::NODE_TYPE_TABLE = "ConfigurationNode";
00971 const std::string ConfigurationTree::NODE_TYPE_GROUP_LINK = "GroupLinkNode";
00972 const std::string ConfigurationTree::NODE_TYPE_UID_LINK = "UIDLinkNode";
00973 const std::string ConfigurationTree::NODE_TYPE_VALUE = "ValueNode";
00974 const std::string ConfigurationTree::NODE_TYPE_UID = "UIDNode";
00975 const std::string ConfigurationTree::NODE_TYPE_ROOT = "RootNode";
00976
00977 std::string ConfigurationTree::getNodeType(void) const
00978 {
00979 if(!configuration_) return ConfigurationTree::NODE_TYPE_ROOT;
00980 if(isConfigurationNode() && groupId_ != "") return ConfigurationTree::NODE_TYPE_GROUP_TABLE;
00981 if(isConfigurationNode()) return ConfigurationTree::NODE_TYPE_TABLE;
00982 if(isGroupLinkNode()) return ConfigurationTree::NODE_TYPE_GROUP_LINK;
00983 if(isLinkNode()) return ConfigurationTree::NODE_TYPE_UID_LINK;
00984 if(isValueNode()) return ConfigurationTree::NODE_TYPE_VALUE;
00985 return ConfigurationTree::NODE_TYPE_UID;
00986 }
00987
00988
00989
00990
00991 bool ConfigurationTree::isGroupLinkNode(void) const
00992 {
00993 return (isLinkNode() && groupId_ != "");
00994 }
00995
00996
00997
00998
00999 bool ConfigurationTree::isUIDLinkNode(void) const
01000 {
01001 return (isLinkNode() && groupId_ == "");
01002 }
01003
01004
01005
01006
01007 bool ConfigurationTree::isUIDNode(void) const
01008 {
01009 return (row_ != ConfigurationView::INVALID && col_ == ConfigurationView::INVALID);
01010 }
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029 std::vector<ConfigurationTree::RecordField> ConfigurationTree::getCommonFields(
01030 const std::vector<std::string /*uid*/> &recordList,
01031 const std::vector<std::string /*relative-path*/> &fieldAcceptList,
01032 const std::vector<std::string /*relative-path*/> &fieldRejectList,
01033 unsigned int depth) const
01034 {
01035
01036 if(!isRootNode() && !isConfigurationNode())
01037 {
01038 __SS__ << "Can only get getCommonFields from a root or table node! " <<
01039 "The node type is " << getNodeType() << std::endl;
01040 __COUT__ << "\n" << ss.str() << std::endl;
01041 throw std::runtime_error(ss.str());
01042 }
01043
01044 std::vector<ConfigurationTree::RecordField> fieldCandidateList;
01045 std::vector<int> fieldCount;
01046
01047 --depth;
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082 bool found;
01083
01084
01085 for(unsigned int i=0;i<recordList.size();++i)
01086 {
01087
01088
01089 auto recordChildren = getNode(recordList[i]).getChildren();
01090 for(const auto &fieldNode : recordChildren)
01091 {
01092
01093
01094 if(fieldNode.second.isValueNode())
01095 {
01096
01097 if(fieldNode.second.getColumnInfo().getType() ==
01098 ViewColumnInfo::TYPE_AUTHOR ||
01099 fieldNode.second.getColumnInfo().getType() ==
01100 ViewColumnInfo::TYPE_TIMESTAMP)
01101 continue;
01102
01103
01104 if(!i)
01105 {
01106
01107 found = fieldAcceptList.size()?false:true;
01108 for(const auto &fieldFilter : fieldAcceptList)
01109 if(ConfigurationTree::wildCardMatch(
01110 fieldFilter,fieldNode.first))
01111 {
01112 found = true;
01113 break;
01114 }
01115
01116
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144 if(found)
01145 {
01146
01147
01148 found = true;
01149 for(const auto &fieldFilter : fieldRejectList)
01150 if(ConfigurationTree::wildCardMatch(
01151 fieldFilter,fieldNode.first))
01152 {
01153 found = false;
01154 break;
01155 }
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185 }
01186
01187
01188 if(found)
01189 {
01190 fieldCandidateList.push_back(
01191 ConfigurationTree::RecordField(
01192 fieldNode.second.getConfigurationName(),
01193 recordList[i],
01194 fieldNode.first,
01195 "",
01196 &fieldNode.second.getColumnInfo()
01197 ));
01198 fieldCount.push_back(-1);
01199 }
01200 }
01201
01202
01203 }
01204 else if(depth > 0 &&
01205 fieldNode.second.isUIDLinkNode() &&
01206 !fieldNode.second.isDisconnected())
01207 {
01208
01209 fieldNode.second.recursiveGetCommonFields(
01210 fieldCandidateList,
01211 fieldCount,
01212 fieldAcceptList,
01213 fieldRejectList,
01214 depth,
01215 fieldNode.first + "/",
01216 !i
01217 );
01218 }
01219 }
01220
01221 }
01222
01223
01224
01225
01226
01227
01228 for(unsigned int i=0;i<fieldCandidateList.size();++i)
01229 {
01230
01231
01232
01233 if(fieldCount[i] != -1 &&
01234 fieldCount[i] != (int)recordList.size())
01235 {
01236
01237
01238
01239 fieldCount.erase(fieldCount.begin() + i);
01240 fieldCandidateList.erase(fieldCandidateList.begin() + i);
01241 --i;
01242 }
01243 }
01244
01245
01246
01247
01248
01249 return fieldCandidateList;
01250 }
01251
01252
01253
01254
01255
01256
01257 std::set<std::string > ConfigurationTree::getUniqueValuesForField(
01258 const std::vector<std::string /*relative-path*/> &recordList,
01259 const std::string &fieldName) const
01260 {
01261
01262 if(!isConfigurationNode())
01263 {
01264 __SS__ << "Can only get getCommonFields from a table node! " <<
01265 "The node type is " << getNodeType() << std::endl;
01266 __COUT__ << "\n" << ss.str() << std::endl;
01267 throw std::runtime_error(ss.str());
01268 }
01269
01270 std::set<std::string > uniqueValues;
01271
01272
01273
01274
01275
01276
01277 for(unsigned int i=0;i<recordList.size();++i)
01278 {
01279 __COUT__ << "Checking " << recordList[i] << std::endl;
01280
01281
01282
01283
01284
01285
01286
01287 uniqueValues.emplace(getNode(recordList[i]).getNode(fieldName).getValueAsString(true));
01288 }
01289
01290 return uniqueValues;
01291 }
01292
01293
01294
01295
01296 void ConfigurationTree::recursiveGetCommonFields(
01297 std::vector<ConfigurationTree::RecordField> &fieldCandidateList,
01298 std::vector<int> &fieldCount,
01299 const std::vector<std::string /*relative-path*/> &fieldAcceptList,
01300 const std::vector<std::string /*relative-path*/> &fieldRejectList,
01301 unsigned int depth,
01302 const std::string &relativePathBase,
01303 bool inFirstRecord
01304 ) const
01305 {
01306 --depth;
01307
01308
01309
01310
01311
01312
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328 bool found;
01329 auto tableName = getConfigurationName();
01330 auto uid = getUIDAsString();
01331 unsigned int j;
01332
01333 auto recordChildren = getChildren();
01334 for(const auto &fieldNode : recordChildren)
01335 {
01336 if(fieldNode.second.isValueNode())
01337 {
01338
01339 if(fieldNode.second.getColumnInfo().getType() ==
01340 ViewColumnInfo::TYPE_AUTHOR ||
01341 fieldNode.second.getColumnInfo().getType() ==
01342 ViewColumnInfo::TYPE_TIMESTAMP)
01343 continue;
01344
01345
01346 if(inFirstRecord)
01347 {
01348
01349 found = fieldAcceptList.size()?false:true;
01350 for(const auto &fieldFilter : fieldAcceptList)
01351 if(ConfigurationTree::wildCardMatch(
01352 fieldFilter,fieldNode.first))
01353 {
01354 found = true;
01355 break;
01356 }
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387 if(found)
01388 {
01389
01390
01391 found = true;
01392 for(const auto &fieldFilter : fieldRejectList)
01393 if(ConfigurationTree::wildCardMatch(
01394 fieldFilter,fieldNode.first))
01395 {
01396 found = false;
01397 break;
01398 }
01399
01400
01401
01402
01403
01404
01405
01406
01407
01408
01409
01410
01411
01412
01413
01414
01415
01416
01417
01418
01419
01420
01421
01422
01423
01424
01425
01426
01427
01428 }
01429
01430
01431 if(found)
01432 {
01433
01434
01435 fieldCandidateList.push_back(
01436 ConfigurationTree::RecordField(
01437 tableName,
01438 uid,
01439 fieldNode.first,
01440 relativePathBase,
01441 &fieldNode.second.getColumnInfo()
01442 ));
01443 fieldCount.push_back(1);
01444 }
01445 }
01446 else
01447 {
01448
01449
01450 for(j=0;j<fieldCandidateList.size();++j)
01451 {
01452 if((relativePathBase + fieldNode.first) ==
01453 (fieldCandidateList[j].relativePath_ +
01454 fieldCandidateList[j].columnName_))
01455 {
01456
01457
01458
01459 ++fieldCount[j];
01460 break;
01461 }
01462 }
01463 }
01464 }
01465 else if(depth > 0 &&
01466 fieldNode.second.isUIDLinkNode() &&
01467 !fieldNode.second.isDisconnected())
01468 {
01469
01470 fieldNode.second.recursiveGetCommonFields(
01471 fieldCandidateList,
01472 fieldCount,
01473 fieldAcceptList,
01474 fieldRejectList,
01475 depth,
01476 (relativePathBase + fieldNode.first) + "/",
01477 inFirstRecord
01478 );
01479 }
01480 }
01481 }
01482
01483
01484
01485
01486
01487 std::vector<std::pair<std::string,ConfigurationTree> > ConfigurationTree::getChildren(
01488 std::map<std::string /*relative-path*/, std::string /*value*/> filterMap) const
01489 {
01490 std::vector<std::pair<std::string,ConfigurationTree> > retMap;
01491
01492
01493
01494 bool filtering = filterMap.size();
01495 bool skip;
01496 std::string fieldValue;
01497
01498 std::vector<std::string> childrenNames = getChildrenNames();
01499 for(auto &childName : childrenNames)
01500 {
01501
01502
01503 if(filtering)
01504 {
01505
01506 skip = false;
01507
01508
01509 for(const auto &filterPair:filterMap)
01510 {
01511 std::string filterPath = childName + "/" + filterPair.first;
01512 try
01513 {
01514
01515
01516 std::istringstream f(filterPair.second);
01517
01518 skip = true;
01519
01520 while (getline(f, fieldValue, ','))
01521 {
01522
01523
01524
01525
01526
01527
01528
01529 __COUT__ << "\t\tCheck: " << filterPair.first <<
01530 " == " << fieldValue << " ??? " <<
01531 this->getNode(filterPath).getValueAsString(true) <<
01532 std::endl;
01533
01534 if(ConfigurationTree::wildCardMatch(
01535 ConfigurationView::decodeURIComponent(fieldValue),
01536 this->getNode(filterPath).getValueAsString(true) ))
01537 {
01538
01539 skip = false;
01540 break;
01541 }
01542
01543
01544
01545
01546
01547
01548
01549
01550 }
01551 }
01552 catch(...)
01553 {
01554 __SS__ << "Failed to access filter path '" <<
01555 filterPath << "' - aborting." << std::endl;
01556 __COUT_ERR__ << "\n" << ss.str();
01557 throw std::runtime_error(ss.str());
01558 }
01559
01560 if(skip) break;
01561 }
01562
01563 if(skip) continue;
01564
01565 __COUT__ << "\tChild accepted: " << childName << std::endl;
01566 }
01567
01568 retMap.push_back(std::pair<std::string,ConfigurationTree>(childName,
01569 this->getNode(childName, true)));
01570 }
01571
01572
01573 return retMap;
01574 }
01575
01576
01577
01578
01579
01580 bool ConfigurationTree::wildCardMatch(const std::string& needle, const std::string& haystack)
01581 try
01582 {
01583
01584
01585
01586
01587 if(needle.size() == 0)
01588 return true;
01589
01590 if(needle[0] == '*' &&
01591 needle[needle.size()-1] == '*' )
01592 return std::string::npos != haystack.find(needle.substr(1,needle.size()-2));
01593
01594 if(needle[0] == '*')
01595 return needle.substr(1) ==
01596 haystack.substr(haystack.size() - (needle.size()-1));
01597
01598 if(needle[needle.size()-1] == '*')
01599 return needle.substr(0,needle.size()-1) ==
01600 haystack.substr(0,needle.size()-1);
01601
01602
01603 return needle == haystack;
01604 }
01605 catch(...)
01606 {
01607 return false;
01608 }
01609
01610
01611
01612
01613
01614 std::map<std::string,ConfigurationTree> ConfigurationTree::getChildrenMap(void) const
01615 {
01616 std::map<std::string,ConfigurationTree> retMap;
01617
01618
01619
01620 std::vector<std::string> childrenNames = getChildrenNames();
01621 for(auto& childName : childrenNames)
01622 {
01623
01624 retMap.insert(std::pair<std::string,ConfigurationTree>(childName, this->getNode(childName)));
01625 }
01626
01627
01628 return retMap;
01629 }
01630
01631
01632 bool ConfigurationTree::isRootNode(void) const
01633 {
01634 return (!configuration_);
01635 }
01636
01637
01638 bool ConfigurationTree::isConfigurationNode(void) const
01639 {
01640 return (configuration_ &&
01641 row_ == ConfigurationView::INVALID && col_ == ConfigurationView::INVALID);
01642 }
01643
01644
01645
01646
01647 std::vector<std::string> ConfigurationTree::getChildrenNames(void) const
01648 {
01649 std::vector<std::string> retSet;
01650
01651 if(!configView_)
01652 {
01653 __SS__ << "Can not get children names of '" <<
01654 getValueAsString() <<
01655 "' with null configuration view pointer!" << std::endl;
01656 if(isLinkNode() && isDisconnected())
01657 ss << " This node is a disconnected link to " <<
01658 getDisconnectedTableName() << std::endl;
01659 __COUT_ERR__ << "\n" << ss.str();
01660 throw std::runtime_error(ss.str());
01661 }
01662
01663 if(row_ == ConfigurationView::INVALID && col_ == ConfigurationView::INVALID)
01664 {
01665
01666
01667
01668 for(unsigned int r = 0; r<configView_->getNumberOfRows(); ++r)
01669 if(groupId_ == "" ||
01670 configView_->isEntryInGroup(r,childLinkIndex_,groupId_))
01671
01672
01673 retSet.push_back(configView_->getDataView()[r][configView_->getColUID()]);
01674 }
01675 else if(row_ == ConfigurationView::INVALID)
01676 {
01677 __SS__ << "Malformed ConfigurationTree" << std::endl;
01678 __COUT_ERR__ << ss.str();
01679 throw std::runtime_error(ss.str());
01680 }
01681 else if(col_ == ConfigurationView::INVALID)
01682 {
01683
01684
01685
01686 for(unsigned int c = 0; c<configView_->getNumberOfColumns(); ++c)
01687 if(c == configView_->getColUID() ||
01688 configView_->getColumnInfo(c).isChildLinkGroupID() ||
01689 configView_->getColumnInfo(c).isChildLinkUID())
01690 continue;
01691 else
01692 retSet.push_back(configView_->getColumnInfo(c).getName());
01693 }
01694 else
01695 {
01696
01697 __SS__ << "\n\nError occurred looking for children of nodeName=" << getValueName() << "\n\n" <<
01698 "Invalid depth! getChildrenValues() called from a value point in the Configuration Tree." << std::endl;
01699 __COUT_ERR__ << ss.str();
01700 throw std::runtime_error(ss.str());
01701 }
01702
01703 return retSet;
01704 }
01705
01706
01707
01708
01709
01710
01711 ConfigurationTree ConfigurationTree::getValueAsTreeNode(void) const
01712 {
01713
01714
01715
01716 if(!configView_)
01717 {
01718 __SS__ << "Invalid node for get value." << std::endl;
01719 __COUT__ << ss.str();
01720 throw std::runtime_error(ss.str());
01721 }
01722
01723 std::string valueString = configView_->getValueAsString(row_,col_,true );
01724
01725 if(valueString.size() && valueString[0] == '/')
01726 {
01727
01728 try
01729 {
01730 ConfigurationTree retNode = configMgr_->getNode(valueString);
01731 __COUT__ << "Found a valid tree path in value!" << std::endl;
01732 return retNode;
01733 }
01734 catch(...)
01735 {
01736 __SS__ << "Invalid tree path." << std::endl;
01737
01738 throw std::runtime_error(ss.str());
01739 }
01740 }
01741
01742
01743 {
01744 __SS__ << "Invalid value string '" << valueString <<
01745 "' - must start with a '/' character." << std::endl;
01746 throw std::runtime_error(ss.str());
01747 }
01748 }
01749
01750
01751
01752
01753
01754
01755
01756
01757
01758
01759