00001 #include "otsdaq-core/ConfigurationDataFormats/ConfigurationInfoReader.h"
00002 #include "otsdaq-core/ConfigurationDataFormats/ConfigurationBase.h"
00003 #include "otsdaq-core/XmlUtilities/DOMTreeErrorReporter.h"
00004 #include "otsdaq-core/XmlUtilities/ConvertFromXML.h"
00005 #include "otsdaq-core/Macros/StringMacros.h"
00006
00007
00008
00009
00010 #include <xercesc/parsers/XercesDOMParser.hpp>
00011 #include <xercesc/dom/DOMElement.hpp>
00012 #include <xercesc/dom/DOMImplementation.hpp>
00013 #include <xercesc/dom/DOMImplementationRegistry.hpp>
00014 #include <xercesc/dom/DOMNodeList.hpp>
00015 #include <xercesc/dom/DOMText.hpp>
00016
00017
00018 #include <xercesc/util/OutOfMemoryException.hpp>
00019 #include <xercesc/framework/LocalFileFormatTarget.hpp>
00020
00021 #include <stdexcept>
00022 #include <iostream>
00023 #include <sstream>
00024
00025 #include <sys/stat.h>
00026 #include <errno.h>
00027
00028 using namespace ots;
00029
00030 #undef __COUT_HDR__
00031 #define __COUT_HDR__ "ConfigInfoReader"
00032
00033
00034
00035 ConfigurationInfoReader::ConfigurationInfoReader(bool allowIllegalColumns)
00036 : allowIllegalColumns_(allowIllegalColumns)
00037 {
00038 initPlatform();
00039 rootTag_ = xercesc::XMLString::transcode("ROOT");
00040 configurationTag_ = xercesc::XMLString::transcode("CONFIGURATION");
00041 configurationNameAttributeTag_ = xercesc::XMLString::transcode("Name");
00042 viewTag_ = xercesc::XMLString::transcode("VIEW");
00043 viewNameAttributeTag_ = xercesc::XMLString::transcode("Name");
00044 viewTypeAttributeTag_ = xercesc::XMLString::transcode("Type");
00045 viewDescriptionAttributeTag_ = xercesc::XMLString::transcode("Description");
00046 columnTag_ = xercesc::XMLString::transcode("COLUMN");
00047 columnTypeAttributeTag_ = xercesc::XMLString::transcode("Type");
00048 columnNameAttributeTag_ = xercesc::XMLString::transcode("Name");
00049 columnStorageNameAttributeTag_ = xercesc::XMLString::transcode("StorageName");
00050 columnDataTypeAttributeTag_ = xercesc::XMLString::transcode("DataType");
00051 columnDataChoicesAttributeTag_ = xercesc::XMLString::transcode("DataChoices");
00052 }
00053
00054
00055 ConfigurationInfoReader::~ConfigurationInfoReader(void)
00056 {
00057 try
00058 {
00059 xercesc::XMLString::release( &rootTag_ );
00060 xercesc::XMLString::release( &configurationTag_ );
00061 xercesc::XMLString::release( &configurationNameAttributeTag_ );
00062 xercesc::XMLString::release( &viewTag_ );
00063 xercesc::XMLString::release( &viewNameAttributeTag_ );
00064 xercesc::XMLString::release( &viewTypeAttributeTag_ );
00065 xercesc::XMLString::release( &viewDescriptionAttributeTag_ );
00066 xercesc::XMLString::release( &columnTag_ );
00067 xercesc::XMLString::release( &columnTypeAttributeTag_ );
00068 xercesc::XMLString::release( &columnNameAttributeTag_ );
00069 xercesc::XMLString::release( &columnStorageNameAttributeTag_ );
00070 xercesc::XMLString::release( &columnDataTypeAttributeTag_ );
00071 xercesc::XMLString::release( &columnDataChoicesAttributeTag_ );
00072
00073 }
00074 catch( ... )
00075 {
00076 mf::LogError(__FILE__) << "Unknown exception encountered in TagNames destructor" << std::endl;
00077 }
00078 terminatePlatform();
00079 }
00080
00081
00082 void ConfigurationInfoReader::initPlatform(void)
00083 {
00084 try
00085 {
00086 xercesc::XMLPlatformUtils::Initialize();
00087 }
00088 catch( xercesc::XMLException& e )
00089 {
00090 mf::LogError(__FILE__) << "XML toolkit initialization error: " << XML_TO_CHAR(e.getMessage()) << std::endl;
00091
00092 }
00093 }
00094
00095
00096 void ConfigurationInfoReader::terminatePlatform(void)
00097 {
00098 try
00099 {
00100 xercesc::XMLPlatformUtils::Terminate();
00101 }
00102 catch( xercesc::XMLException& e )
00103 {
00104 mf::LogError(__FILE__) << "XML tolkit teardown error: " << XML_TO_CHAR(e.getMessage()) << std::endl;
00105 }
00106 }
00107
00108
00109
00110 void ConfigurationInfoReader::setAllowColumnErrors(bool setValue)
00111 {
00112 allowIllegalColumns_ = setValue;
00113 }
00114
00115 const bool& ConfigurationInfoReader::getAllowColumnErrors(void)
00116 {
00117 return allowIllegalColumns_;
00118 }
00119
00120
00121 bool ConfigurationInfoReader::checkViewType(std::string type)
00122 {
00123 std::vector<std::string> types;
00124 int currentIndex = 0;
00125 while( type.find(',',currentIndex) != std::string::npos )
00126 {
00127 types.push_back(type.substr(currentIndex,type.find(',',currentIndex)-currentIndex));
00128 currentIndex = type.find(',',currentIndex)+1;
00129 }
00130 types.push_back(type.substr(currentIndex,type.size()));
00131
00132 std::string systemType = getenv("CONFIGURATION_TYPE");
00133 for(unsigned int i=0; i<types.size(); i++)
00134 {
00135 if( types[i] == systemType )
00136 return true;
00137 }
00138
00139 const unsigned int allowedNamesSize = 3;
00140 const std::string allowedNames[allowedNamesSize] =
00141 {"File","Database","DatabaseTest"
00142 };
00143 if(systemType != allowedNames[0] && systemType != allowedNames[1] && systemType != allowedNames[2] )
00144 {
00145 __COUT__ << "The type defined in CONFIGURATION_TYPE ("
00146 << systemType << ") doesn't match with any of the allowed types: File,Database or DatabaseTest"
00147 << std::endl;
00148
00149 throw(std::runtime_error( "Illegal configuration type" ));
00150 }
00151 for(unsigned int i=0; i<types.size(); i++)
00152 {
00153 if(types[i] != allowedNames[0] && types[i] != allowedNames[1] && types[i] != allowedNames[2] )
00154 {
00155 __COUT__ << "The type defined in the info file ("
00156 << types[i] << ") doesn't match with any of the allowed types: "
00157 << allowedNames[0] << ", " << allowedNames[1] << " or " << allowedNames[2]
00158 << std::endl;
00159 throw(std::runtime_error( "Illegal Type!" ));
00160 }
00161 }
00162
00163 return false;
00164 }
00165
00166
00167 xercesc::DOMNode* ConfigurationInfoReader::getNode(XMLCh* tagName, xercesc::DOMNode* parent, unsigned int itemNumber)
00168 {
00169 return getNode(tagName, dynamic_cast< xercesc::DOMElement* >(parent), itemNumber);
00170 }
00171
00172
00173 xercesc::DOMNode* ConfigurationInfoReader::getNode(XMLCh* tagName, xercesc::DOMElement* parent, unsigned int itemNumber)
00174 {
00175 xercesc::DOMNodeList* nodeList = parent->getElementsByTagName(tagName);
00176 if( !nodeList )
00177 {
00178 throw(std::runtime_error( std::string("Can't find ") + XML_TO_CHAR(tagName) + " tag!"));
00179 __COUT__ << (std::string("Can't find ") + XML_TO_CHAR(tagName) + " tag!") << std::endl;
00180 }
00181
00182
00183
00184 return nodeList->item(itemNumber);
00185 }
00186
00187
00188 xercesc::DOMElement* ConfigurationInfoReader::getElement(XMLCh* tagName, xercesc::DOMNode* parent, unsigned int itemNumber)
00189 {
00190 return dynamic_cast< xercesc::DOMElement* >(getNode(tagName,parent,itemNumber));
00191 }
00192
00193
00194 xercesc::DOMElement* ConfigurationInfoReader::getElement(XMLCh* tagName, xercesc::DOMElement* parent, unsigned int itemNumber)
00195 {
00196 return dynamic_cast< xercesc::DOMElement* >(getNode(tagName,parent,itemNumber));
00197 }
00198
00199
00200 std::string ConfigurationInfoReader::read(ConfigurationBase& configuration)
00201 {
00202 std::string accumulatedExceptions = "";
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213 if(getenv("CONFIGURATION_TYPE" ) == NULL) __COUT__ << "Missing env variable: CONFIGURATION_TYPE. It must be set!" << std::endl;
00214 if(getenv("CONFIGURATION_DATA_PATH") == NULL) __COUT__ << "Missing env variable: CONFIGURATION_DATA_PATH. It must be set!" << std::endl;
00215 if(getenv("CONFIGURATION_INFO_PATH") == NULL) __COUT__ << "Missing env variable: CONFIGURATION_INFO_PATH. It must be set!" << std::endl;
00216
00217
00218
00219
00220
00221
00222
00223
00224 std::string configurationDataDir = std::string(getenv("CONFIGURATION_INFO_PATH")) + "/";
00225 std::string configFile = configurationDataDir + configuration.getConfigurationName() + "Info.xml";
00226
00227 struct stat fileStatus;
00228
00229 int iretStat = stat(configFile.c_str(), &fileStatus);
00230 if( iretStat == ENOENT )
00231 {
00232 __SS__ << ("Path file_name does not exist, or path is an empty std::string.") << std::endl;
00233 __COUT_ERR__ << ss.str();
00234 throw std::runtime_error(ss.str());
00235 }
00236 else if( iretStat == ENOTDIR )
00237 {
00238 __SS__ << ("A component of the path is not a directory.") << std::endl;
00239 __COUT_ERR__ << ss.str();
00240 throw std::runtime_error(ss.str());
00241 }
00242 else if( iretStat == ELOOP )
00243 {
00244 __SS__ << ("Too many symbolic links encountered while traversing the path.") << std::endl;
00245 __COUT_ERR__ << ss.str();
00246 throw std::runtime_error(ss.str());
00247 }
00248 else if( iretStat == EACCES )
00249 {
00250 __SS__ << ("Permission denied.") << std::endl;
00251 __COUT_ERR__ << ss.str();
00252 throw std::runtime_error(ss.str());
00253 }
00254 else if( iretStat == ENAMETOOLONG )
00255 {
00256 __SS__ << ("File can not be read. Name too long.") << std::endl;
00257 __COUT_ERR__ << ss.str();
00258 throw std::runtime_error(ss.str());
00259 }
00260
00261 xercesc::XercesDOMParser* parser = new xercesc::XercesDOMParser;
00262
00263 parser->setValidationScheme(xercesc::XercesDOMParser::Val_Auto);
00264 parser->setDoNamespaces ( true );
00265 parser->setDoSchema ( true );
00266 parser->useCachedGrammarInParse ( false );
00267
00268 DOMTreeErrorReporter* errorHandler = new DOMTreeErrorReporter() ;
00269 parser->setErrorHandler(errorHandler);
00270 try
00271 {
00272 parser->parse( configFile.c_str() );
00273
00274
00275 xercesc::DOMDocument* xmlDocument = parser->getDocument();
00276
00277
00278 xercesc::DOMElement* elementRoot = xmlDocument->getDocumentElement();
00279 if( !elementRoot )
00280 {
00281 delete parser;
00282 delete errorHandler;
00283 throw(std::runtime_error( "empty XML document" ));
00284 }
00285
00286
00287 xercesc::DOMElement* configurationElement = getElement(configurationTag_, elementRoot, 0);
00288 if( configuration.getConfigurationName() != XML_TO_CHAR(configurationElement->getAttribute(configurationNameAttributeTag_)) )
00289 {
00290
00291 __SS__ << "In " << configFile << " the configuration name " << XML_TO_CHAR(configurationElement->getAttribute(configurationNameAttributeTag_))
00292 << " doesn't match the the class configuration name " << configuration.getConfigurationName() << std::endl;
00293
00294 delete parser;
00295 delete errorHandler;
00296 __COUT_ERR__ << "\n" << ss.str();
00297 throw(std::runtime_error( ss.str()));
00298 }
00299
00300 xercesc::DOMNodeList* viewNodeList = configurationElement->getElementsByTagName(viewTag_);
00301 bool storageTypeFound = false;
00302
00303 if(viewNodeList->getLength() != 1)
00304 {
00305
00306 __SS__ << "In " << configFile << " the configuration name " << XML_TO_CHAR(configurationElement->getAttribute(configurationNameAttributeTag_))
00307 << " there must only be one view. There were " <<
00308 viewNodeList->getLength() << " found." << std::endl;
00309
00310 delete parser;
00311 delete errorHandler;
00312 __COUT_ERR__ << "\n" << ss.str();
00313 throw(std::runtime_error( ss.str()));
00314 }
00315
00316 for( XMLSize_t view = 0; view < viewNodeList->getLength(); view++ )
00317 {
00318 if( !viewNodeList->item(view)->getNodeType() || viewNodeList->item(view)->getNodeType() != xercesc::DOMNode::ELEMENT_NODE )
00319 continue;
00320 xercesc::DOMElement* viewElement = dynamic_cast< xercesc::DOMElement* >( viewNodeList->item(view) );
00321 std::string viewType = XML_TO_CHAR(viewElement->getAttribute(viewTypeAttributeTag_));
00322 if(!checkViewType(viewType))
00323 continue;
00324 storageTypeFound = true;
00325 configuration.getMockupViewP()->setTableName(XML_TO_CHAR(viewElement->getAttribute(viewNameAttributeTag_)));
00326 xercesc::DOMNodeList* columnNodeList = viewElement->getElementsByTagName(columnTag_);
00327 for( XMLSize_t column = 0; column < columnNodeList->getLength(); column++ )
00328 {
00329
00330 xercesc::DOMElement* columnElement = dynamic_cast< xercesc::DOMElement* >( columnNodeList->item(column) );
00331
00332
00333
00334 std::string capturedException;
00335 configuration.getMockupViewP()->getColumnsInfoP()->push_back(
00336 ViewColumnInfo(
00337 XML_TO_CHAR(columnElement->getAttribute(columnTypeAttributeTag_)),
00338 XML_TO_CHAR(columnElement->getAttribute(columnNameAttributeTag_)),
00339 XML_TO_CHAR(columnElement->getAttribute(columnStorageNameAttributeTag_)),
00340 XML_TO_CHAR(columnElement->getAttribute(columnDataTypeAttributeTag_)),
00341 XML_TO_CHAR(columnElement->getAttribute(columnDataChoicesAttributeTag_)),
00342 allowIllegalColumns_?&capturedException:0));
00343
00344
00345
00346 if(capturedException != "")
00347 accumulatedExceptions += std::string("\n\nColumn Error:") + capturedException;
00348
00349
00350 }
00351
00352
00353
00354 std::string configurationDescription = XML_TO_CHAR(viewElement->getAttribute(
00355 viewDescriptionAttributeTag_));
00356
00357 configuration.setConfigurationDescription(
00358 StringMacros::decodeURIComponent(configurationDescription));
00359
00360
00361
00362 }
00363 if( !storageTypeFound )
00364 {
00365 __COUT__ << "The type defined in CONFIGURATION_TYPE ("
00366 << getenv("CONFIGURATION_TYPE") << ") doesn't match with any of the types defined in " << configFile << std::endl;
00367
00368 delete parser;
00369 delete errorHandler;
00370 throw(std::runtime_error( "Configuration Type mismatch!" ));
00371 }
00372
00373
00374 }
00375 catch( xercesc::XMLException& e )
00376 {
00377 std::ostringstream errBuf;
00378 errBuf << "Error parsing file: " << XML_TO_CHAR(e.getMessage()) << std::flush;
00379 }
00380 delete parser;
00381 delete errorHandler;
00382
00383
00384
00385
00386
00387
00388 return accumulatedExceptions;
00389 }
00390
00391
00392
00393
00394 std::string ConfigurationInfoReader::read(ConfigurationBase* configuration)
00395 {
00396 return read(*configuration);
00397 }