$treeview $search $mathjax $extrastylesheet
otsdaq
v2_03_00
$projectbrief
|
$projectbrief
|
$searchbox |
00001 #include "otsdaq-core/TableCore/TableInfoReader.h" 00002 00003 #include "otsdaq-core/Macros/StringMacros.h" 00004 #include "otsdaq-core/XmlUtilities/ConvertFromXML.h" 00005 #include "otsdaq-core/XmlUtilities/DOMTreeErrorReporter.h" 00006 00007 //#include "TimeFormatter.h" 00008 00009 #include <xercesc/dom/DOMElement.hpp> 00010 #include <xercesc/dom/DOMImplementation.hpp> 00011 #include <xercesc/dom/DOMImplementationRegistry.hpp> 00012 #include <xercesc/dom/DOMNodeList.hpp> 00013 #include <xercesc/dom/DOMText.hpp> 00014 #include <xercesc/parsers/XercesDOMParser.hpp> 00015 //#include <xercesc/dom/DOMWriter.hpp> 00016 00017 #include <xercesc/framework/LocalFileFormatTarget.hpp> 00018 #include <xercesc/util/OutOfMemoryException.hpp> 00019 00020 #include <iostream> 00021 #include <sstream> 00022 #include <stdexcept> 00023 00024 #include <errno.h> 00025 #include <sys/stat.h> 00026 00027 #include "otsdaq-core/TableCore/TableBase.h" 00028 00029 using namespace ots; 00030 00031 #undef __COUT_HDR__ 00032 #define __COUT_HDR__ "TableInfoReader" 00033 00034 // const std::string TableInfoReader::CONFIGURATION_BACKEND_TYPE_ = 00035 // getenv("CONFIGURATION_TYPE"); 00036 #define CONFIGURATION_BACKEND_TYPE_ getenv("CONFIGURATION_TYPE") 00037 00038 //============================================================================== 00039 TableInfoReader::TableInfoReader(bool allowIllegalColumns) 00040 : allowIllegalColumns_(allowIllegalColumns) 00041 { 00042 initPlatform(); 00043 rootTag_ = xercesc::XMLString::transcode("ROOT"); 00044 tableTag_ = xercesc::XMLString::transcode("TABLE"); 00045 tableNameAttributeTag_ = xercesc::XMLString::transcode("Name"); 00046 viewTag_ = xercesc::XMLString::transcode("VIEW"); 00047 viewNameAttributeTag_ = xercesc::XMLString::transcode("Name"); 00048 viewTypeAttributeTag_ = xercesc::XMLString::transcode("Type"); 00049 viewDescriptionAttributeTag_ = xercesc::XMLString::transcode("Description"); 00050 columnTag_ = xercesc::XMLString::transcode("COLUMN"); 00051 columnTypeAttributeTag_ = xercesc::XMLString::transcode("Type"); 00052 columnNameAttributeTag_ = xercesc::XMLString::transcode("Name"); 00053 columnStorageNameAttributeTag_ = xercesc::XMLString::transcode("StorageName"); 00054 columnDataTypeAttributeTag_ = xercesc::XMLString::transcode("DataType"); 00055 columnDataChoicesAttributeTag_ = xercesc::XMLString::transcode("DataChoices"); 00056 } 00057 00058 //============================================================================== 00059 TableInfoReader::~TableInfoReader(void) 00060 { 00061 try 00062 { 00063 xercesc::XMLString::release(&rootTag_); 00064 xercesc::XMLString::release(&tableTag_); 00065 xercesc::XMLString::release(&tableNameAttributeTag_); 00066 xercesc::XMLString::release(&viewTag_); 00067 xercesc::XMLString::release(&viewNameAttributeTag_); 00068 xercesc::XMLString::release(&viewTypeAttributeTag_); 00069 xercesc::XMLString::release(&viewDescriptionAttributeTag_); 00070 xercesc::XMLString::release(&columnTag_); 00071 xercesc::XMLString::release(&columnTypeAttributeTag_); 00072 xercesc::XMLString::release(&columnNameAttributeTag_); 00073 xercesc::XMLString::release(&columnStorageNameAttributeTag_); 00074 xercesc::XMLString::release(&columnDataTypeAttributeTag_); 00075 xercesc::XMLString::release(&columnDataChoicesAttributeTag_); 00076 } 00077 catch(...) 00078 { 00079 __COUT_ERR__ << "Unknown exception encountered in TagNames destructor" << __E__; 00080 } 00081 terminatePlatform(); 00082 } 00083 00084 //============================================================================== 00085 void TableInfoReader::initPlatform(void) 00086 { 00087 try 00088 { 00089 xercesc::XMLPlatformUtils::Initialize(); // Initialize Xerces infrastructure 00090 } 00091 catch(xercesc::XMLException& e) 00092 { 00093 __COUT_ERR__ << "XML toolkit initialization error: " 00094 << XML_TO_CHAR(e.getMessage()) << __E__; 00095 // throw exception here to return ERROR_XERCES_INIT 00096 } 00097 } 00098 00099 //============================================================================== 00100 void TableInfoReader::terminatePlatform(void) 00101 { 00102 try 00103 { 00104 xercesc::XMLPlatformUtils::Terminate(); // Terminate after release of memory 00105 } 00106 catch(xercesc::XMLException& e) 00107 { 00108 __COUT_ERR__ << "XML tolkit teardown error: " << XML_TO_CHAR(e.getMessage()) 00109 << __E__; 00110 } 00111 } 00112 00113 //============================================================================== 00114 void TableInfoReader::setAllowColumnErrors(bool setValue) 00115 { 00116 allowIllegalColumns_ = setValue; 00117 } 00118 //============================================================================== 00119 const bool& TableInfoReader::getAllowColumnErrors(void) { return allowIllegalColumns_; } 00120 00121 //============================================================================== 00122 bool TableInfoReader::checkViewType(std::string type) 00123 { 00124 std::vector<std::string> types; 00125 int currentIndex = 0; 00126 while(type.find(',', currentIndex) != std::string::npos) 00127 { 00128 types.push_back( 00129 type.substr(currentIndex, type.find(',', currentIndex) - currentIndex)); 00130 currentIndex = type.find(',', currentIndex) + 1; 00131 } 00132 types.push_back(type.substr(currentIndex, type.size())); 00133 00134 const std::string systemType = CONFIGURATION_BACKEND_TYPE_; 00135 00136 for(unsigned int i = 0; i < types.size(); i++) 00137 { 00138 if(types[i] == systemType) 00139 return true; 00140 } 00141 // In case I don't succeed let's check if maybe there is something wrong with the 00142 // names 00143 const unsigned int allowedNamesSize = 3; 00144 const std::string allowedNames[allowedNamesSize] = { 00145 "File", "Database", "DatabaseTest"}; 00146 if(systemType != allowedNames[0] && systemType != allowedNames[1] && 00147 systemType != allowedNames[2]) 00148 { 00149 __COUT__ << "The type defined in CONFIGURATION_BACKEND_TYPE (" << systemType 00150 << ") doesn't match with any of the allowed types: File,Database or " 00151 "DatabaseTest" 00152 << __E__; 00153 00154 throw(std::runtime_error("Illegal table type")); 00155 } 00156 for(unsigned int i = 0; i < types.size(); i++) 00157 { 00158 if(types[i] != allowedNames[0] && types[i] != allowedNames[1] && 00159 types[i] != allowedNames[2]) 00160 { 00161 __COUT__ << "The type defined in the info file (" << types[i] 00162 << ") doesn't match with any of the allowed types: " 00163 << allowedNames[0] << ", " << allowedNames[1] << " or " 00164 << allowedNames[2] << __E__; 00165 throw(std::runtime_error("Illegal Type!")); 00166 } 00167 } 00168 00169 return false; 00170 } 00171 00172 //============================================================================== 00173 xercesc::DOMNode* TableInfoReader::getNode(XMLCh* tagName, 00174 xercesc::DOMNode* parent, 00175 unsigned int itemNumber) 00176 { 00177 return getNode(tagName, dynamic_cast<xercesc::DOMElement*>(parent), itemNumber); 00178 } 00179 00180 //============================================================================== 00181 xercesc::DOMNode* TableInfoReader::getNode(XMLCh* tagName, 00182 xercesc::DOMElement* parent, 00183 unsigned int itemNumber) 00184 { 00185 xercesc::DOMNodeList* nodeList = parent->getElementsByTagName(tagName); 00186 if(!nodeList) 00187 { 00188 throw(std::runtime_error(std::string("Can't find ") + XML_TO_CHAR(tagName) + 00189 " tag!")); 00190 __COUT__ << (std::string("Can't find ") + XML_TO_CHAR(tagName) + " tag!") 00191 << __E__; 00192 } 00193 // __COUT__<< "Name: " << XML_TO_CHAR(nodeList->item(itemNumber)->getNodeName()) 00194 // << __E__; if( nodeList->item(itemNumber)->getFirstChild() != 0 ) 00195 // __COUT__<< "Value: " << 00196 // XML_TO_CHAR(nodeList->item(itemNumber)->getFirstChild()->getNodeValue()) << 00197 // __E__; 00198 return nodeList->item(itemNumber); 00199 } 00200 00201 //============================================================================== 00202 xercesc::DOMElement* TableInfoReader::getElement(XMLCh* tagName, 00203 xercesc::DOMNode* parent, 00204 unsigned int itemNumber) 00205 { 00206 return dynamic_cast<xercesc::DOMElement*>(getNode(tagName, parent, itemNumber)); 00207 } 00208 00209 //============================================================================== 00210 xercesc::DOMElement* TableInfoReader::getElement(XMLCh* tagName, 00211 xercesc::DOMElement* parent, 00212 unsigned int itemNumber) 00213 { 00214 return dynamic_cast<xercesc::DOMElement*>(getNode(tagName, parent, itemNumber)); 00215 } 00216 00217 //============================================================================== 00218 std::string TableInfoReader::read(TableBase& table) 00219 { 00220 std::string accumulatedExceptions = ""; 00221 00222 // KEEP For debugging... added by Gennadiy... 00223 // if table name starts with "TestTable00" then turn off the reading of information 00224 // auto tmp_test_table_prefix = std::string{"TestTable00"}; 00225 // auto tmp_table_name = table.getTableName(); 00226 // if (std::equal(tmp_test_table_prefix.begin(), tmp_test_table_prefix.end(), 00227 // tmp_table_name.begin())) return accumulatedExceptions; KEEP End debugging... for 00228 // Gennadiy... 00229 00230 // These environment variables are required 00231 if(getenv("CONFIGURATION_TYPE") == NULL) 00232 __COUT__ << "Missing env variable: CONFIGURATION_TYPE. It must be set!" << __E__; 00233 // if(getenv("CONFIGURATION_DATA_PATH") == NULL) __COUT__ << "Missing env variable: 00234 // CONFIGURATION_DATA_PATH. It must be set!" << __E__; 00235 if(getenv("TABLE_INFO_PATH") == NULL) 00236 __COUT__ << "Missing env variable: TABLE_INFO_PATH. It must be set!" << __E__; 00237 00238 // example c++ setting of necessary environment variables 00239 // setenv("CONFIGURATION_TYPE","File",1); 00240 // setenv("CONFIGURATION_DATA_PATH",(std::string(getenv("USER_DATA")) + 00241 // "/TableDataExamples").c_str(),1); 00242 // setenv("TABLE_INFO_PATH",(std::string(getenv("USER_DATA")) + 00243 // "/TableInfo").c_str(),1); 00244 00245 std::string tableDataDir = std::string(getenv("TABLE_INFO_PATH")) + "/"; 00246 std::string tableFile = tableDataDir + table.getTableName() + "Info.xml"; 00247 //__COUT__ << tableFile << __E__; 00248 struct stat fileStatus; 00249 00250 int iretStat = stat(tableFile.c_str(), &fileStatus); 00251 if(iretStat == ENOENT) 00252 { 00253 __SS__ << ("Path file_name does not exist, or path is an empty std::string.") 00254 << __E__; 00255 __COUT_ERR__ << ss.str(); 00256 __SS_THROW__; 00257 } 00258 else if(iretStat == ENOTDIR) 00259 { 00260 __SS__ << ("A component of the path is not a directory.") << __E__; 00261 __COUT_ERR__ << ss.str(); 00262 __SS_THROW__; 00263 } 00264 else if(iretStat == ELOOP) 00265 { 00266 __SS__ << ("Too many symbolic links encountered while traversing the path.") 00267 << __E__; 00268 __COUT_ERR__ << ss.str(); 00269 __SS_THROW__; 00270 } 00271 else if(iretStat == EACCES) 00272 { 00273 __SS__ << ("Permission denied.") << __E__; 00274 __COUT_ERR__ << ss.str(); 00275 __SS_THROW__; 00276 } 00277 else if(iretStat == ENAMETOOLONG) 00278 { 00279 __SS__ << ("File can not be read. Name too long.") << __E__; 00280 __COUT_ERR__ << ss.str(); 00281 __SS_THROW__; 00282 } 00283 00284 xercesc::XercesDOMParser* parser = new xercesc::XercesDOMParser; 00285 // Configure DOM parser. 00286 parser->setValidationScheme(xercesc::XercesDOMParser::Val_Auto); // Val_Never 00287 parser->setDoNamespaces(true); 00288 parser->setDoSchema(true); 00289 parser->useCachedGrammarInParse(false); 00290 00291 DOMTreeErrorReporter* errorHandler = new DOMTreeErrorReporter(); 00292 parser->setErrorHandler(errorHandler); 00293 try 00294 { 00295 parser->parse(tableFile.c_str()); 00296 00297 // no need to free this pointer - owned by the parent parser object 00298 xercesc::DOMDocument* xmlDocument = parser->getDocument(); 00299 00300 // Get the top-level element: Name is "root". No attributes for "root" 00301 xercesc::DOMElement* elementRoot = xmlDocument->getDocumentElement(); 00302 if(!elementRoot) 00303 { 00304 delete parser; 00305 delete errorHandler; 00306 throw(std::runtime_error("empty XML document")); 00307 } 00308 00309 //<TABLE> 00310 xercesc::DOMElement* tableElement = getElement(tableTag_, elementRoot, 0); 00311 if(table.getTableName() != 00312 XML_TO_CHAR(tableElement->getAttribute(tableNameAttributeTag_))) 00313 { 00314 __SS__ << "In " << tableFile << " the table name " 00315 << XML_TO_CHAR(tableElement->getAttribute(tableNameAttributeTag_)) 00316 << " doesn't match the the class table name " << table.getTableName() 00317 << __E__; 00318 00319 delete parser; 00320 delete errorHandler; 00321 __COUT_ERR__ << "\n" << ss.str(); 00322 throw(std::runtime_error(ss.str())); 00323 } 00324 //<VIEW> 00325 xercesc::DOMNodeList* viewNodeList = tableElement->getElementsByTagName(viewTag_); 00326 bool storageTypeFound = false; 00327 00328 if(viewNodeList->getLength() != 1) 00329 { 00330 __SS__ << "In " << tableFile << " the table name " 00331 << XML_TO_CHAR(tableElement->getAttribute(tableNameAttributeTag_)) 00332 << " there must only be one view. There were " 00333 << viewNodeList->getLength() << " found." << __E__; 00334 00335 delete parser; 00336 delete errorHandler; 00337 __COUT_ERR__ << "\n" << ss.str(); 00338 throw(std::runtime_error(ss.str())); 00339 } 00340 00341 for(XMLSize_t view = 0; view < viewNodeList->getLength(); view++) 00342 { 00343 if(!viewNodeList->item(view)->getNodeType() || 00344 viewNodeList->item(view)->getNodeType() != 00345 xercesc::DOMNode::ELEMENT_NODE) // true is not 0 && is element 00346 continue; 00347 xercesc::DOMElement* viewElement = 00348 dynamic_cast<xercesc::DOMElement*>(viewNodeList->item(view)); 00349 std::string viewType = 00350 XML_TO_CHAR(viewElement->getAttribute(viewTypeAttributeTag_)); 00351 if(!checkViewType(viewType)) 00352 continue; 00353 storageTypeFound = true; 00354 table.getMockupViewP()->setTableName( 00355 XML_TO_CHAR(viewElement->getAttribute(viewNameAttributeTag_))); 00356 xercesc::DOMNodeList* columnNodeList = 00357 viewElement->getElementsByTagName(columnTag_); 00358 for(XMLSize_t column = 0; column < columnNodeList->getLength(); column++) 00359 { 00360 //<COLUMN> 00361 xercesc::DOMElement* columnElement = 00362 dynamic_cast<xercesc::DOMElement*>(columnNodeList->item(column)); 00363 //__COUT__ << 00364 // XML_TO_CHAR(columnElement->getAttribute(columnNameAttributeTag_)) << 00365 // __E__; 00366 00367 // automatically delete the persistent version of the column info 00368 std::string capturedException; 00369 table.getMockupViewP()->getColumnsInfoP()->push_back(TableViewColumnInfo( 00370 XML_TO_CHAR(columnElement->getAttribute(columnTypeAttributeTag_)), 00371 XML_TO_CHAR(columnElement->getAttribute(columnNameAttributeTag_)), 00372 XML_TO_CHAR( 00373 columnElement->getAttribute(columnStorageNameAttributeTag_)), 00374 XML_TO_CHAR(columnElement->getAttribute(columnDataTypeAttributeTag_)), 00375 XML_TO_CHAR( 00376 columnElement->getAttribute(columnDataChoicesAttributeTag_)), 00377 allowIllegalColumns_ 00378 ? &capturedException 00379 : 0)); // capture exception string if allowing illegal columns 00380 00381 // if error detected (this implies allowing illegal columns) 00382 // accumulate and return accumulated errors at end 00383 if(capturedException != "") 00384 accumulatedExceptions += 00385 std::string("\n\nColumn Error:") + capturedException; 00386 00387 //</COLUMN> 00388 } 00389 00390 // handle view description (which is actually the table 00391 // description since only one view allowed) 00392 std::string tableDescription = 00393 XML_TO_CHAR(viewElement->getAttribute(viewDescriptionAttributeTag_)); 00394 00395 table.setTableDescription(StringMacros::decodeURIComponent(tableDescription)); 00396 //__COUT__ << "tableDescription = " << tableDescription << __E__; 00397 00398 //</VIEW> 00399 } 00400 if(!storageTypeFound) 00401 { 00402 __COUT__ << "The type defined in CONFIGURATION_BACKEND_TYPE (" 00403 << CONFIGURATION_BACKEND_TYPE_ 00404 << ") doesn't match with any of the types defined in " << tableFile 00405 << __E__; 00406 00407 delete parser; 00408 delete errorHandler; 00409 throw(std::runtime_error("Table Type mismatch!")); 00410 } 00411 00412 //</TABLE> 00413 } 00414 catch(xercesc::XMLException& e) 00415 { 00416 std::ostringstream errBuf; 00417 errBuf << "Error parsing file: " << XML_TO_CHAR(e.getMessage()) << std::flush; 00418 } 00419 delete parser; 00420 delete errorHandler; 00421 00422 //__COUT__ << __E__; 00423 00424 // if exceptions have been accumulated 00425 // then in allowIllegalColumns mode 00426 // return accumulated exception strings to next level 00427 return accumulatedExceptions; 00428 } 00429 00430 //============================================================================== 00431 // returns accumulated exception string (while allowIllegalColumns == true) 00432 // otherwise "" if no exceptions 00433 std::string TableInfoReader::read(TableBase* table) { return read(*table); }